gpt4 book ai didi

c++ - 通过调用 constexpr 函数定义静态 constexpr 成员

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:07:33 25 4
gpt4 key购买 nike

我的问题如下。我想根据 constexpr 值列表对类型列表进行排序。问题可以归结为这个函数:

template <typename U, typename V>
auto min(U,V) -> std::conditional_t<U::value < V::value, U, V>
{ return {}; }

而 value 必须分别是每种类型的一些静态 constexpr 成员。以下片段演示了用法:

// (I)

// This must even be declared outside of a function body due to the statics :(
struct X { static constexpr double value = 2.; };
struct Y { static constexpr double value = 1.; };

int main()
{
X x;
Y y;
auto z = min(x,y);
std::cout << typeid(z).name() << " : " << z.value << std::endl;
}

我的目标是在调用函数时提供值。我最接近这个目标的是以下

template <double (*F)()>
struct Value { static constexpr double value = F(); };

可以使用 lambda 像这样调用:

// (II)
auto w = min(Value<[]{ return 3.14; }>{}, Value<[]{ return 2.71; }>{});
std::cout << typeid(w).name() << " : " << w.value << std::endl;

要排序的实际类型可以是附加参数。

问题是,根据标准,以上内容不是有效的 C++。但是,最新的 clang 确实可以编译这很优雅。

现在,我的问题是:是否有另一种符合标准的方式来实现上述目标(列表(II)),即定义一个函数根据就地(以某种方式)作为函数参数提供的 constexor 对象计算类型?


P.S.:我知道使用 std::integral_constant 的解决方案。但是,这仅限于整数类型。我对适用于所有 constexpr 对象的解决方案很感兴趣,尤其是浮点类型和字符串。

最佳答案

编辑:

要处理浮点值和整数类型场景,您可以使用用户定义的文字模板,例如:

#include <type_traits>
#include <utility>
#include <typeinfo>
#include <iostream>

template <class FloatingPointType, class... Cs>
constexpr FloatingPointType char_list_to_(Cs... cs) {
char arr[] = {cs...};
FloatingPointType lhs = 0;
bool contains_dot = false;
for (std::size_t i = 0; i < sizeof...(Cs) && !(contains_dot |= (arr[i] == '.')); i++) {
lhs *= 10;
lhs += arr[i] - '0';
}
FloatingPointType rhs = 0;
for (int i = sizeof...(Cs) - 1; i > 0 && arr[i] != '.'; i--) {
rhs /= 10;
rhs += arr[i] - '0';
}
rhs /= 10;
return (contains_dot)?lhs+rhs:lhs;
}

template <class FloatingPointType, char... Cs>
struct FloatingPointValue {

static constexpr FloatingPointType value = char_list_to_<FloatingPointType>(Cs...);

constexpr operator FloatingPointType() {
return value;
}
};

template <class FloatingPointType, char... Cs>
constexpr FloatingPointType FloatingPointValue<FloatingPointType, Cs...>::value;

template <char... Cs>
FloatingPointValue<double, Cs...> operator""_fv() {
return {};
}


template <typename U, typename V>
auto min(U,V) -> std::conditional_t<(U{}<V{}), U, V>
{ return {}; }

int main() {
auto w = min(3.14_fv, 2.71_fv);
std::cout << typeid(w).name() << " : " << w.value << std::endl;
}

输出:

18FloatingPointValueIdJLc50ELc46ELc55ELc49EEE : 2.71

c++filt -t 18FloatingPointValueIdJLc50ELc46ELc55ELc49EEE 的输出:

FloatingPointValue<double, (char)50, (char)46, (char)55, (char)49>

[live demo]


但是,如果您希望将相同的方法应用于字符串文字,目前由于 c++ 标准而缺乏对该功能的支持。但是,如果您能够接受不太便携的选项,则有 clang 和 gcc 支持的 gnu 扩展:

#include <type_traits>
#include <utility>
#include <typeinfo>
#include <iostream>

template <class CharT, CharT... Cs>
struct Value {

static constexpr std::size_t size = sizeof...(Cs);
static constexpr CharT const value[sizeof...(Cs) + 1] = {Cs..., '\0'};

template <class RHS>
constexpr bool operator<(RHS) {
for (std::size_t i = 0; i < size && i < RHS::size; i++) {
if (value[i] != RHS::value[i]) {
return value[i] < RHS::value[i];
}
}
return size < RHS::size;
}
};

template <class CharT, CharT... Cs>
constexpr CharT const Value<CharT, Cs...>::value[sizeof...(Cs) + 1];

template <class CharT, CharT... Cs>
Value<CharT, Cs...> operator""_v() {
return {};
}


template <typename U, typename V>
auto min(U,V) -> std::conditional_t<(U{}<V{}), U, V>
{ return {}; }

int main() {
auto w = min("cde"_v, "abc"_v);
std::cout << typeid(w).name() << " : " << w.value << std::endl;
}

输出:

5ValueIcJLc97ELc98ELc99EEE : abc

c++filt -t 5ValueIcJLc97ELc98ELc99EEE 的输出:

Value<char, (char)97, (char)98, (char)99>

[live demo]

关于c++ - 通过调用 constexpr 函数定义静态 constexpr 成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44777398/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com