【问题标题】:(Partially) specializing a non-type template parameter of dependent type(部分)特化依赖类型的非类型模板参数
【发布时间】:2022-01-15 23:47:51
【问题描述】:

也许我累了,但我被这个简单的部分专业化困住了,因为non-type template argument specializes a template parameter with dependent type 'T'

template <typename T, T N> struct X;
template <typename T>      struct X <T, 0>;

0 替换为T(0)T{0}(T)0 没有帮助。那么这种专业化是否可能?

【问题讨论】:

    标签: c++ templates partial-specialization non-type


    【解决方案1】:

    参见标准的 [temp.class.spec] 14.5.5/8 段:

    模板参数的类型对应于一个专门的 非类型参数不应依赖于 专业化。 [ 例子:

    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
    

    ——结束示例 ]

    您的编辑的答案:最简单的解决方法是将非类型模板参数替换为类型一:

    #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>> {};
    

    【讨论】:

    • 谢谢。我找到了一种解决方法(请参阅已编辑的问题) - 有更好的主意吗?
    • @iavr 我已经编辑了我的答案,以便为您的编辑提供解决方案。
    • 太好了,我已将其与我的第一次尝试结合起来,请参阅编辑后的答案。
    • 我无法解释原因,但GCC cannot disambiguate 在您的解决方案的一般定义和专业化之间。 Clang 工作正常。
    • @iavr gcc 接受它,如果你在专业化中将0 转换为Tcoliru.stacked-crooked.com/a/435ff04ca4640ae8
    【解决方案2】:

    使用Yakk的解决方案:

    #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

    【讨论】:

    • 有趣,我以前没有这样用过enable_if。我在这里选择了一种不同的方法(见编辑),但我会记住这一点,因为我猜它在检查一个或多个模板参数的任意条件时更通用。
    • @iavr 您的解决方案非常巧妙,如果我是您,我可能会坚持使用它(当然还有评论!)
    • @iavr 对于它的价值,我的解决方案可以使用指针,而您的 EDIT 2 解决方案不能。但您可能不需要该功能。
    • 对,我在这里处理数字。但是enable_if 肯定更通用。
    【解决方案3】:

    您可以将typename=void 参数添加到template 参数列表的末尾,然后在专业化中使用std::enable_if_t&lt; 条件&gt;

    【讨论】:

    【解决方案4】:

    您需要在模板中传递一个整数值,如果类型 T 不是整数类型,您的第一个和第二个模板都将不起作用。

    您可以将 Traits 作为类型化模板参数传递以指定值 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;
    }
    

    如果您将自己限制为整数类型,请选择一个大的:

    template <typename T, std::size_t N = 0> struct X {};
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-01
      相关资源
      最近更新 更多