类模板的模板参数推导可以用于非类型模板参数吗?

时间:2017-03-01 23:02:19

标签: c++ templates c++17

以下类可以利用template argument deduction for class templates吗?

template <int I>
struct Number
{
    /* appropriate constructor here */
}; 

通过“利用”我的意思是,有没有办法(隐式地或明确地)推导出I的价值?示例用法如下:

Number a(3); // a's type is Number<3>

3 个答案:

答案 0 :(得分:5)

类模板的模板参数推导可以推导非类型模板参数,但不是你想要的方式。

例如

template <std::size_t size>
struct ArrayWrapper {
    ArrayWrapper(std::array<int, size> a);
};
int main() {
    std:array<int, 5> a;
    ArrayWrapper aw(a);  // ok; declares ArrayWrapper<5>
}

但是在您的示例中,您尝试从参数的推导出非类型模板参数。通常,C ++的模板推导系统不支持该类,无论是用于类模板还是用于任何其他上下文。

答案 1 :(得分:3)

构造函数的模板推导仍然是演绎 - 并且演绎都是关于类型的。推导值的唯一方法是该值是否是推导类型之一的非类型模板参数。因此,我们只需将3从无聊的旧int提升为复杂的现代std::integral_constant<int, 3>

template <int I> using int_t = std::integral_constant<int, I>;
template <int I> constexpr int_t<I> int_c;

template <int I>
struct Number {
    Number(int_t<I> ) { }
};

int main()
{
    Number n(int_c<3> );
}

值得注意的是,此功能的目的是避免重复写入类型(例如使用std::lock_guard),或者命名类型的情况可能是不可能的(例如使用lambda构造的类模板特化) 。这些都不适用于这里。当你有一个值 - 那就是它,只需使用值:

Number<3> n;

Number n{3}相同数量的字符,这些字符不起作用,因此无法获得。

答案 2 :(得分:-2)

我正在分享我的(部分)解决方案:

#include <iostream>
#include <type_traits>

template <int I>
struct Number
{
    // 1. 
    Number(int) {}
};

// 2. 
template <int K> Number(std::integral_constant<int, K>) -> Number<K>; 

int main()
{
    Number a{std::integral_constant<int, 1>{}}; // look ma, no \<>/
    (void)a; 
    return 0; 
}

Demo

我们对上面编号的评论所做的是:

  1. 一个参数构造函数。当我们传递积分常量时,这可以作为转换构造函数(注释掉它并得到编译错误)

  2. 明确的扣除规则

  3. 所有这些购买我们的是声明Number对象而不指定模板参数的能力,即仅仅让构造函数推导出它们。不幸的是,这个解决方案没有优雅,因为构造要求一个整数常量(然后隐式转换为整数):

    Number a{std::integral_constant<int, 1>{}}; // a := Number<int>
    

    更进一步的是设计一种简单的写作方式:

    Number a{3}; 
    

    但明确的扣除规则不适用于非类型模板参数,或者至少我不能欺骗它工作。