c++templatesassertionstatic-assert

Is there something like templated static_asserts in C++?


It is possible to check for the existence of class member functions. An implementation of the check could be taken from this answer: https://stackoverflow.com/a/257382/2492801.

Now a static_assert can be used to ensure that a certain class has an implementation of a needed method. But if the class is templated, I do not know whether such a static assertion is possible or how to do it - except if I do the static_assert for a concrete template parameter selection. The latter is possible, but it feels wrong...

Please consider the following code:

#include <iostream>

// SFINAE test
template <typename T>
class has_helloworld
{
    typedef char one;
    struct two
    {
        char x[2];
    };

    template <typename C>
    static one test(decltype(&C::helloworld));
    template <typename C>
    static two test(...);

  public:
    enum
    {
        value = sizeof(test<T>(0)) == sizeof(char)
    };
};

template <int number>
struct Hello
{
    int helloworld()
    {
        return 0;
    }

    // The next line is not possible since class Hello is not complete yet.
    // static_assert(has_helloworld<Hello<number>>::value);
};

template <int number>
struct Generic
{
};

int main()
{
    // This is possible, but I don't like it
    static_assert(has_helloworld<Hello<3>>::value);

    // The next two lines are not possible because a template declaration cannot appear at block scope.
    // template <int number>
    // static_assert(has_helloworld<Hello<number>>::value);

    std::cout << has_helloworld<Hello<2>>::value << std::endl;
    std::cout << has_helloworld<Generic<2>>::value << std::endl;

    return 0;
}

Here is a Godbolt link: https://godbolt.org/z/c3bKKMxcc

Is there a possibility in C++ to do a "templated static assert", so a static_assert where I check a property of a class that depends on a template parameter without choosing a dummy value for that parameter?

Clarification: In my case in practice the template parameter does not play a role, it just impedes the static_assert. So like in the code example, all template structs Hello have the required method regardless of the parameter number.


Solution

  • Template classes are not classes.

    Template classes generate classes.

    Asking if a template class has a specific member is a category error. It is like asking if a specific type of paper has mountains drawn on it.

    You might say "but I know that this paper is always used to draw maps of the rockies!" C++ doesn't know this, it just knows you are talking about paper.

    The mapping of template class plus parameters to class is a Turing complete computation. This process cannot be inverted in the general case - for a template class X<A>, you cannot answer the question "what properties does X<> have for an arbitrary A".

    When designing the template system for C++, the computational model chosen was too strong to be inverted like that.

    It is true that the most typical use of templates uses a far weaker set of computational capabilities - most uses of templates are a step removed from macros with basic meta type checking.

    As a concrete example, a template class can be written such that Hello<N> has a specific property if and only if the Collatz conjecture is true for the constant N, and it accepts bignums as arguments.

    In order to know the properties of Hello<?> for an arbitrary argument, the compiler would have to prove the Collatz conjecture.

    Now, you might say, "I'm not doing that". Too bad; C++ doesn't say "so long as the person writing the template doesn't do anything fancy, you can invert the template mapping and solves this problem".

    It could; it could define a weaker set of template mechanics that can be safely inverted without hitting this problem. A number of languages do exactly that (Generics in Java, which both weaken the kind of mapping you can do and have a rather different implementation; C#'s version is a bit stronger than Java, but also weakens C++ templates in a somewhat similar way).