如果已知则使用编译时常量

时间:2016-10-17 03:07:02

标签: c++ templates compile-time

我有一些神秘类型<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.1/moment.min.js"></script>的值(对于这个例子,我们可以假设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; 被用作模板参数,即使我从未直接在实例化中使用它的值。

1 个答案:

答案 0 :(得分:5)

是的,你可以这样做。使用Johannes Schaub's trick,我们可以执行以下操作:

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