4

私の問題は次のとおりです。私はconstexpr値のリストに基づいて型のリストをソートしたい。問題は、この機能に煮詰めすることができる。constexpr関数の呼び出しによって静的なconstexprメンバを定義する

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

一方値がrespecively、各タイプのいくつかの静的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; 
} 

私の目標は、私は関数を呼び出すと価値を提供することです。

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

実際の型は、追加のパラメータとすることができますソートする:私はこの目標になった最も近いものは 次

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

次のように呼び出すことができます使用してラムダです。

問題は、上記のものが標準のC++でないことです。しかし、最新のclang はこれを正常にコンパイルします

今、私の質問は、上記の(リスト(II))を達成するための標準に準拠したもう1つの方法、すなわち、 がある場所で(何らかの方法で)提供されたconstexorオブジェクトに基づいて型を計算する関数を定義していますか?関数の引数?


P .:私はstd::integral_constantを使用して解決策を認識しています。ただし、これは整数型に限定されています。私は、すべてのconstexprオブジェクト、特に浮動小数点型、および文字列で機能するソリューションに興味があります。

+0

好奇心を要らずに:これは標準に準拠していないのはなぜですか? – KjMag

+0

@KjMag [この質問](https://stackoverflow.com/questions/44485610/will-i-be-able-to-declare-constexpr-lambda-inside-a-template-parameter)を参照してください。 – Rakete1111

答えて

2

編集:

#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++の標準に起因する機能のサポートの欠如は、現在存在しています。あなたが少ないポータブルオプションを受け入れることが可能であれば打ち鳴らすと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; 
} 

出力:c++filt -t 5ValueIcJLc97ELc98ELc99EEE

5ValueIcJLc97ELc98ELc99EEE : abc 

出力:

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

[live demo]

+0

それは実際に文字列のための素晴らしいソリューションです。残念ながらgccに限定されており、浮動小数点値への拡張方法はわかりません。ここで文字列はcharの可変長テンプレートリストとして渡されますが、浮動小数点に対してはこれを行うことはできません。私は解決しようとしているのと同じ状況になるだろう - 静的なメンバーの中に浮動小数点を隠している。 –

+0

@AndréBergnerあなたは静的メンバーに浮動小数点を格納する必要がありますが、浮動小数点をインラインで作成する必要があります。 'max(" 3.14 "_vf"、 "2.71" _vf) "と呼びます。 Value型の演算子の負担を軽減するために、この努力は沸騰します。 PS。 clangもそれをサポートしています...そしてそれを標準化する提案があります。残念ながら、あなたはC++ 17ではなく、おそらくC++ 20でそれを取得しません...誰が知っていますか?私はそれに私の指を渡しています:) –

+0

@AndréBergner実際には既に数値化されたユーザー定義のリテラルテンプレートが存在することが判明しています(例:[here](http://en.cppreference.com/w/cpp/ language/user_literal))これはアプローチをよりポータブルにするでしょう。 'max(3.14_vf、2.71_vf)' –