首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过调用constexpr函数来定义静态constexpr成员

通过调用constexpr函数来定义静态constexpr成员
EN

Stack Overflow用户
提问于 2017-06-27 09:59:47
回答 1查看 739关注 0票数 4

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

代码语言:javascript
复制
template <typename U, typename V>
auto min(U,V) -> std::conditional_t<U::value < V::value, U, V>
{ return {}; }

而值必须是每种类型的静态成员,相应地。下面的代码片段演示了使用情况:

代码语言:javascript
复制
// (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;
}

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

代码语言:javascript
复制
template <double (*F)()>
struct Value { static constexpr double value = F(); };

它可以像这样使用lambdas调用:

代码语言:javascript
复制
// (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对象,特别是浮点类型和字符串。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-06-27 13:13:14

编辑:

要处理浮点值以及积分类型场景,可以使用用户定义的文字模板,例如:

代码语言:javascript
复制
#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;
}

输出:

代码语言:javascript
复制
18FloatingPointValueIdJLc50ELc46ELc55ELc49EEE : 2.71

c++filt -t 18FloatingPointValueIdJLc50ELc46ELc55ELc49EEE输出

代码语言:javascript
复制
FloatingPointValue<double, (char)50, (char)46, (char)55, (char)49>

[现场演示]

但是,如果您希望将同样的内容应用于字符串文字,那么c++标准造成的特性目前缺乏支持。但是,如果您能够接受较少的可移植选项,则有一个由clang和gcc支持的gnu扩展:

代码语言:javascript
复制
#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;
}

输出:

代码语言:javascript
复制
5ValueIcJLc97ELc98ELc99EEE : abc

c++filt -t 5ValueIcJLc97ELc98ELc99EEE输出

代码语言:javascript
复制
Value<char, (char)97, (char)98, (char)99>

[现场演示]

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44777398

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档