I'm trying to determine at compile time if a specific type is of type std::pair. When I compile the code below, I get the assertion fail on both branches (that is, both "HERE1", and "HERE2"). If I remove the static_asserts and uncomment the prints, I get what I expect: That is "HERE1" for is_pair_type<T::value_type>, and "HERE2" for is_pair_type< T >.
I guess this means the compiler can't evaluate the expression at compile time, but I don't understand why.
Using: MS VS2019, with MSVC version 14.29.30037
Thanks.
template< class T > struct is_pair : std::false_type {};
template< class T1, class T2 > struct is_pair< std::pair< T1, T2 > > : std::true_type {};
template< class T > struct is_pair_d : is_pair<typename std::decay<T>::type> {};
// a helper function for value
template<class T> struct is_pair_type {
static constexpr bool const value = is_pair_d<T>::value;
};
int main()
{
using T = std::map<int, float>;
T blabla;
if constexpr (is_pair_type<T>::value)
{
//std::cout << "HERE1" << "\n";
static_assert(false, "HERE1");
}
else
{
//std::cout << "HERE2" << "\n";
static_assert(false, "HERE2");
}
...
Constexpr if is supposed to work with template:
Outside a template, a discarded statement is fully checked.
if constexpr
is not a substitute for the #if preprocessing directive:void f() { if constexpr(false) { int i = 0; int *p = i; // Error even though in discarded statement } }
And
Note: the discarded statement can't be ill-formed for every possible specialization:
template <typename T> void f() { if constexpr (std::is_arithmetic_v<T>) // ... else static_assert(false, "Must be arithmetic"); // ill-formed: invalid for every T }
You can wrap the code into a function template like:
template<class T> struct dependent_false : std::false_type {};
template <typename T>
void foo() {
if constexpr (is_pair_type<T>::value)
{
std::cout << "HERE1" << "\n";
static_assert(dependent_false<T>::value, "HERE1");
}
else
{
std::cout << "HERE2" << "\n";
static_assert(dependent_false<T>::value, "HERE2");
}
}
Then
using T = std::map<int, float>;
foo<T>(); // static_assert fails only on the else part