【问题标题】:Can template argument deduction for class templates work for non type template parameters?类模板的模板参数推导可以用于非类型模板参数吗?
【发布时间】:2017-03-01 23:02:19
【问题描述】:

像下面这样的类可以利用template argument deduction for class templates吗?

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

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

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

【问题讨论】:

  • 您似乎希望模板为您创建一个构造函数——这是不可能的。
  • @NeilButterworth 不是我的意图,只是如果知道如何拼写特定的构造函数,我就不会问这个问题。我会编辑澄清
  • int 模板参数是编译时的东西 - 在运行时将它传递给构造函数是没有意义的。
  • @NeilButterworth 阅读了我对布赖恩回答的评论
  • 是的,但为什么不简单地Number &lt;3&gt; a;

标签: c++ templates c++17


【解决方案1】:

类模板的模板参数推导可以推导出非类型模板参数,但不能以您尝试的方式进行。

例如

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>
}

但在您的示例中,您试图从参数的 value 推导出一个非类型模板参数。一般来说,C++的模板推演系统不支持,无论是类模板还是其他任何上下文。

【讨论】:

  • 我认为这可以通过 integral_constant 参数(在构造函数中)来完成,但是在将数字转换为整数常量时我被卡住了。也许这可以通过明确的扣除规则来实现???
  • @LorahAttkins 我不这么认为。模板参数推导只考虑参数的类型,而不考虑它们的值
【解决方案2】:

构造函数的模板推导仍然是推导——而推导就是类型。您可以推断出一个值的唯一方法是该值是否是被推断出的类型之一的非类型模板参数。所以我们可以简单地将3从一个无聊的旧int提升到一个复杂、现代的std::integral_constant&lt;int, 3&gt;

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} 的字符数相同,这是行不通的,因此没有任何收获。

【讨论】:

  • 我正在写一个类似的解决方案(在这个解决方案之后 5' 发布)。按照我的看法,您可以使用带有 int 参数的转换构造函数,而推导规则使用整数常量。与我所寻找的相比,这只是一个转换步骤。我认为巧妙地使用类型系统(或三元运算符)可以为我们提供这一点
【解决方案3】:

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

#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

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

  1. 单参数构造函数。这用作我们传递整数常量时的转换构造函数(将其注释掉,您会得到编译错误)

  2. 显式演绎规则

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

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

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

Number a{3}; 

但显式推导规则不适用于非类型模板参数,或者至少我无法欺骗它工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多