Silvio Mayolo - 4 months ago 32

C++ Question

I have a value of some mystery type

`T`

`T`

`std::integral_constant`

`T`

`0`

Currently, I have the following (non-compiling) code.

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

Unfortunately,

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

The compiler doesn't like

`ivalue`

Answer

Yes, you can do this. Using Johannes Schaub's trick, we can do the following:

```
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)>;
```