2016-10-17 2 views
3

J'ai une valeur de type mystère T (pour cet exemple, nous pouvons supposer que T est un type intégral). Je voudrais utiliser cette valeur comme un argument de modèle dans une fonction de modèle (pour cet exemple, l'argument à std::integral_constant). Le problème est que T pourrait ne pas être un type constant. Si ce n'est pas un type constant, je voudrais par défaut 0 dans ma fonction de modèle. Si c'est constant, cependant, j'aimerais utiliser la valeur elle-même, puisqu'elle est connue.Utiliser la constante de compilation si connue

Actuellement, j'ai le code suivant (non-compilation).

#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; 

Malheureusement, g++ donne l'erreur suivante.

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; 

Le compilateur n'aime pas ivalue être utilisé comme un argument de modèle, même si je ne l'utilise jamais directement sa valeur dans l'instanciation.

Répondre

5

Oui, vous pouvez le faire. En utilisant Johannes Schaub's trick, nous pouvons faire ce qui suit:

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 demo.