(Partially) specializing a non-type template parameter of dependent type

前端 未结 4 1884
难免孤独
难免孤独 2020-12-01 04:06

Maybe I\'m tired, but I\'m stuck with this simple partial specialization, which doesn\'t work because non-type template argument specializes a template parameter with

相关标签:
4条回答
  • 2020-12-01 04:15

    See paragraph [temp.class.spec] 14.5.5/8 of the standard:

    The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. [ Example:

    template <class T, T t> struct C {};
    template <class T> struct C<T, 1>; // error
    
    template< int X, int (*array_ptr)[X] > class A {};
    int array[5];
    template< int X > class A<X,&array> { }; // error
    

    —end example ]

    The answer to your edit: the easiest workaround is to replace a non-type template parameter with a type one:

    #include <type_traits>
    
    template <typename T, typename U>
    struct X_;
    
    template <typename T, T N>
    struct X_<T, std::integral_constant<T, N>> {};
    
    template <typename T>
    struct X_<T, std::integral_constant<T, 0>> {};
    
    template <typename T, T N>
    struct X : X_<T, std::integral_constant<T, N>> {};
    
    0 讨论(0)
  • 2020-12-01 04:19

    You need to pass an integral value in a template, Both, your first and second template, will not work if the type T is not an integral type.

    You can pass Traits as a typed template parameter to specify the value N:

    #include <iostream>
    
    // error: ‘double’ is not a valid type for a template non-type parameter
    template <typename T, T N> struct X0;
    
    // error: ‘double’ is not a valid type for a template non-type parameter
    template <typename T, T N, int = 0> struct X1;
    
    
    
    template <typename T, T N>
    struct IntegralTraits {
        static constexpr T Value() { return N; }
    };
    
    template <typename T, typename Traits = void>
    struct X2 {
        static constexpr T Value() { return Traits::Value(); }
    };
    
    template <typename T>
    struct X2<T, void> {
        static constexpr T Value() { return T(); }
    };
    
    
    int main() {
        // error: ‘double’ is not a valid type for a template non-type parameter
        // X0<double, 0>();
    
        // error: ‘double’ is not a valid type for a template non-type parameter
        // X1<double, 0>();
    
        X2<int> a;
        X2<double, IntegralTraits<int, 1>> b;
    
        std::cout.precision(2);
        std::cout << std::fixed  <<  a.Value() << ", "<< b.Value() << '\n';
        return 0;
    }
    

    If you limit yourself to integral types pick a large one:

    template <typename T, std::size_t N = 0> struct X {};
    
    0 讨论(0)
  • You can add a typename=void parameter to the end of the list of template arguments, then go hog wild with std::enable_if_t< condition > in specializations.

    0 讨论(0)
  • 2020-12-01 04:35

    Solution using Yakk's solution:

    #include <iostream>
    #include <type_traits>
    
    template <typename T, T N, typename = void > 
    struct X {
      static const bool isZero = false;
    };
    
    template <typename T, T N>
    struct X < T, N, typename std::enable_if<N == 0>::type > {
      static const bool isZero = true;
    };
    
    int main(int argc, char* argv[]) {
        std::cout << X <int, 0>::isZero << std::endl;
        std::cout << X <int, 1>::isZero << std::endl;
        return 0;
    }
    

    Live Demo

    0 讨论(0)
提交回复
热议问题