2016-10-17 9 views
3

私はいくつかのミステリータイプTの値を持っています(この例では、Tは整数型です)。私はいくつかのテンプレート関数(この例では、std::integral_constantへの引数)のテンプレート引数としてこの値を使用したいと思います。問題は、Tが定数型でない可能性があるということです。定数型でない場合は、テンプレート関数内で0をデフォルトにしたいと思います。しかし、それが一定であれば、わかっているので、値そのものを使用したいと思います。既知の場合はコンパイル時定数を使用します。

現在、私は以下の(コンパイルされていない)コードを持っています。

#include <type_traits> 

template <typename T> 
struct CompileTimeStuff { 
    constexpr static int value(T arg) { return 0; } 
}; 

template <typename T> 
struct CompileTimeStuff<const T> { 
    constexpr static int value(const T arg) { return (int)arg; } 
}; 

template <typename T> 
constexpr int magic_function(T arg) { 
    return CompileTimeStuff<T>::value(arg); 
} 

const int cvalue = 7; 
int ivalue = 7; 

// This should be 7, since cvalue is constant and thus known at compile-time. 
typedef std::integral_constant<int, magic_function(cvalue)> type1; 
// Since ivalue is non-constant, this should take the default value of 0. 
typedef std::integral_constant<int, magic_function(ivalue)> type2; 

残念ながら、g++は次のエラーを示します。

templatestuff.cpp:28:58: error: the value of ‘ivalue’ is not usable in a constant expression 
typedef std::integral_constant<int, magic_function(ivalue)> type2; 

コンパイラは、私が直接インスタンス化して、その値を使用したことがないにもかかわらず、ivalueはテンプレート引数として使用されて好きではありません。

答えて

5

はい、これを行うことができます。

template<typename T> 
constexpr typename std::remove_reference<T>::type makeprval(T && t) { 
    return t; 
} 

#define constexpr_or_zero(e) (noexcept(makeprval(e)) ? (e) : 0) 

const int cvalue = 7; 
int ivalue = 7; 

using type1 = std::integral_constant<int, constexpr_or_zero(cvalue)>; 
using type2 = std::integral_constant<int, constexpr_or_zero(ivalue)>; 

Here's a demoJohannes Schaub's trickを使用して、我々は次の操作を行うことができます。

関連する問題