Question

With variable templates coming in C++14 (and Clang already supporting them) and a proposal for standard is_same_v and likewise type traits, I figured being able to make new type traits as follows would be neat:

template<typename T>
constexpr bool is_const_and_volatile{std::is_const_v<T> && std::is_volatile_v<T>};

Alas, this results in errors equivalent to the following SSCCE (this one contains everything mentioned below):

#include <type_traits>

template<typename T>
constexpr bool is_pointer{std::is_pointer<T>::value};

template<typename T>
constexpr bool foo{is_pointer<T>};

int main() {
    //foo<int *>;
}

With the line in main commented, Clang spits out the following:

warning: variable is_pointer<type-parameter-0-0> has internal linkage but is not defined

It looks defined to me (note that changing T to int * in foo works fine). Uncommenting the line in main to instantiate foo gives this (again, T to int * works fine):

error: constexpr variable foo<int *> must be initialized by a constant expression

However, replacing foo with the following old syntax causes both instances to work fine:

constexpr bool foo{std::is_pointer<T>::value};

Is there something I'm missing about variable templates? Is there a way to build new variable templates with them, or am I forced to use the older syntax to build new ones and only enjoy the syntactic sugar when using them for other code?

Was it helpful?

Solution

Your code is valid, and is accepted by clang SVN. The link error was caused by clang bug 17846, which I fixed a couple of days ago.

OTHER TIPS

The following seems to work:

#include <type_traits>
#include <iostream>

template<typename T>
struct test {
    static constexpr bool is_pointer{std::is_pointer<T>::value};
};

template<typename T>
constexpr bool test<T>::is_pointer;

template<typename T>
constexpr bool foo{test<T>::is_pointer};

int main() {
    std::cout << foo<bool>;
    std::cout << foo<bool*>;
}

Live Example

Although it procs the same warning if used in a constexpr context so I suppose it doesn't really work after all.

// Fail
template<typename T>
typename std::enable_if<foo<T>, void>::type bar()
{
}

int main() {
    bar<bool*>();
}

main.cpp:21:5: error: no matching function for call to 'bar'

    bar<bool*>();

    ^~~~~~~~~~

main.cpp:16:45: note: candidate template ignored: substitution failure [with T = bool *]: non-type template argument is not a constant expression

typename std::enable_if<foo<T>, void>::type bar()

It does stop complaining if you give foo an explicit type:

template<typename T>
typename std::enable_if<foo<bool*>, void>::type bar()
{
}

Or just use test<T>::is_pointer directly:

template<typename T>
typename std::enable_if<test<T>::is_pointer, void>::type bar()
{
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top