【问题标题】:Deduction of templated class member in templated class模板类中模板类成员的扣减
【发布时间】:2021-04-21 02:42:32
【问题描述】:

我正在利用 C++17 的新功能来推断模板类中的类成员类型。具体来说,我正在这样做:

#include <array>
#include <iostream>

template <std::size_t N = 0>
class A
{
public:
    using Array = std::array<int, N>;

    A(const Array& arr) : myArr{arr} {}
    A() = default;

    void show() { std::cout << N << std::endl; }

private:
    Array myArr;
};

当我构造 A 而不明确指出 N 时,编译器会正确匹配构造函数并正确推断出 N

std::array<int, 3> data{1, 2, 3};
A a1{data};
A a2;

a1.show(); // prints 3
a2.show(); // prints 0

但是,当我在A 中引入另一个模板参数时,这个魔法就被破坏了,像这样:

template <typename T, std::size_t N = 0>
class A
{
    ... // same content, no use of T
}

当我像这样构造A 传递任何T 时,它不再编译:

A<int> a1{data};
A<int> a2;

编译器在所有情况下都推导出N=0,并且无法将输入std::array&lt;int, 3&gt;分配给构造函数std::array&lt;int, 0&gt;中的推导参数:

error: no matching function for call to ‘A<int>::A(<brace-enclosed initializer list>)’
A<int> a1{data};

note: candidate: ‘A<T, N>::A(const Array&) [with T = int; long unsigned int N = 0; A<T, N>::Array = std::array<int, 0>]’
A(const Array& arr) : myArr{arr} {}

note:  no known conversion for argument 1 from ‘std::array<int, 3>’ to ‘const Array&’ {aka ‘const std::array<int, 0>&’}
A(const Array& arr) : myArr{arr} {}

谁能解释为什么会发生这种情况以及是否有任何解决方案?

提前谢谢你!

【问题讨论】:

  • 输入A&lt;int&gt;时,指定所有模板参数,N默认为0。没有推论。
  • @S.M.而已!我没有意识到。那么我相信没有办法正确推断N,我需要到处传递T...
  • @DavisHerring 谢谢,这是一个非常接近的答案,但我认为我不能让它在我的情况下工作。如果我为N=0 的情况声明template &lt;typename T&gt; class A -&gt; A&lt;T, 0&gt;,那么我可以在template &lt;typename T, std::size_t N&gt; class A 此处删除N 的默认值。太好了,它将允许A&lt;int&gt; a2;。但是,我不知道如何声明 N&gt;0 而不明确指出 A&lt;int, 3&gt; a1{data}; 的情况。有可能还是我错过了什么?
  • @Victor:我投票支持副本是基于它对困难的解释,而不是其变通方法的适用性。这并不是说不可能有:例如,在 C++20 中,您可以使用类似 wrapper&lt;int&gt;::alias a{data}; 的东西。

标签: c++ templates c++17 member


【解决方案1】:

演绎指南不做部分匹配。

合成与否。

在第一种情况下,编译器合成一个演绎指南。

template<std::size_t N>
A(std::array<int,N>const&)->A<N>;

一旦您传递任何模板参数,就不会使用推导指南。没有部分匹配。

请参阅 https://en.cppreference.com/w/cpp/language/class_template_argument_deduction 以获得对您所谓的魔法的正确描述。

如果需要,可以编写一个 make 函数,或者省略 int

至于为什么,可能是逆向兼容性恐惧和KISS原则。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-25
    相关资源
    最近更新 更多