Search code examples
c++templatesvariadic-templatestemplate-specializationstatic-assert

Variadic template specilization


So I was trying the custom literal operator in order to implement binary literals. However it seems I am doing something wrong with the template specialization. The static_assert is evaluated while it shouldn't:

template <char... bits>
struct bin_imp
{
        static constexpr unsigned long long to_ull()
        {
                static_assert(false,"not binary value");
                return 0;
        }
};

template <char... bits>
struct bin_imp<'0', bits...>
{
        static constexpr unsigned long long to_ull()
        {
                return bin_imp<bits...>::to_ull();
        }
};

template <char... bits>
struct bin_imp<'1', bits...>
{
        static constexpr unsigned long long to_ull()
        {
                return (1ULL << sizeof...(bits)) | bin_imp<bits...>::to_ull();
        }
};


template <>
struct bin_imp<>
{
        static constexpr unsigned long long to_ull()
        {
                return 0;
        }
};

template <char... bits>
static constexpr unsigned long long operator "" _b ()
{
        return bin_imp<bits...>::to_ull();
};

int main(int argc, char* argv[])
{
        unsigned int i = 11_b;
        return 0;
}

Any ideas?


Solution

  • static_assert(false,"not binary value");
    

    The compiler rejects this because it is obvious to the compiler that it will fail, even during the first phase of parsing the source code. The compiler doesn't need to instantiate the class template, in order to know that the static_assert will fail.

    What you can do here is, force the compiler to evaluate the condition in the second phase of parsing — i.e when the function (of the class template) is instantiated. To do that you need a class template, such as this:

     template<char ...>
     struct always_false : std::false_type {};
    

    Now use this as:

    static_assert(always_false<bits...>::value,"not binary value");
    

    Now the compiler cannot evaluate the condition until it instantiates always_false<> which happens to be always false.

    That is, the solution is : being lazy when evaluating the expression.