使用使用成员类型别名的构造函数推导类模板参数

T.C*_*.C. 20 c++ language-lawyer c++17

所以显然这应该工作:

template<class T>
struct C {
   using value_type = T;
   C(value_type);
};

C c(1); // C<int>
Run Code Online (Sandbox Code Playgroud)

就像这样(参见[over.match.class.deduct]/3中B例子):

template<class T>
struct D {
   template<class> using meow_t = T;

   template<class U>
   D(U, meow_t<U>);
};

D d(1, 'c'); // D<char>
Run Code Online (Sandbox Code Playgroud)

请注意,看似等效的显式指南不起作用,因为参数是非推导的上下文:

template<class T>
C(typename C<T>::value_type) -> C<T>;
Run Code Online (Sandbox Code Playgroud)

虽然至少第一个片段的作用当然是可取的,但我还没有找到实际使其在当前工作草案中起作用的措辞.有谁知道它在哪里?

Bar*_*rry 1

严格来说这不是一个答案,因为我认为这样的措辞实际上不存在。这更多的是与问题相关的信息的拼凑。


这是核心问题2。Oulu 和 Issaquah 中关于此功能的讨论清楚地表明,其意图是查看 typedef 是有效的,但没有添加任何措辞来表明它应该如何工作 - 它只是......是的。原样的措辞表明推导指南:

template<class T>
struct C {
   using value_type = T;
   C(value_type);
};
Run Code Online (Sandbox Code Playgroud)

将会:

template <class T> C<T> foo(typename C<T>::value_type );
Run Code Online (Sandbox Code Playgroud)

这将是一个非推导的上下文并且失败,但是[thread.lock.guard]没有针对这种情况的明确的推导指南。

[over.match.best]中的示例显然旨在表明 typedef 应该起作用,尽管该示例中的任何示例实际上都没有使用 #1 作为推导指南:

template <class T> struct A {
  using value_type = T;
  A(value_type);    // #1
  A(const A&);      // #2
  A(T, T, int);     // #3
  template<class U>
    A(int, T, U);   // #4
  // #5 is the copy deduction candidate, A(A)
};

A x(1, 2, 3);       // uses #3, generated from a non-template constructor

template <class T>
A(T) -> A<T>;       // #6, less specialized than #5

A a(42);            // uses #6 to deduce A<int> and #1 to initialize
A b = a;            // uses #5 to deduce A<int> and #2 to initialize

template <class T>
A(A<T>) -> A<A<T>>; // #7, as specialized as #5

A b2 = a;           // uses #7 to deduce A<A<int>> and #1 to initialize
Run Code Online (Sandbox Code Playgroud)

  • 我相信我们在伊萨夸的讨论中描述这一点的方式是“这里发生了剧烈的挥手”。预期的规则是 CWG 2 的规则:如果您可以仅使用模板中的信息来确定类型是什么,那么您就可以针对该类型。(换句话说,如果使用可推导类型重新声明构造函数是有效的,那么您就可以针对该类型进行推导。但这会将您带回到 CWG 2 来确定重新声明何时有效。) (2认同)