c ++模板参数类型推断

Wal*_*Cat 10 c++ templates type-inference inferred-type

我在C++中有这样的模板

template<typename T, T* P> struct Ptr {};
Run Code Online (Sandbox Code Playgroud)

所以我可以这样使用它:

const int i = 0;
Ptr<int, &i> ptr;
Run Code Online (Sandbox Code Playgroud)

要么

Ptr<decltype(i), &i> ptr;
Run Code Online (Sandbox Code Playgroud)

但我不想两次指定类型int或标识i,我只想使用

Ptr<&i> ptr;
Run Code Online (Sandbox Code Playgroud)

让编译器自己找出int类型部分.

如何声明我的模板呢?

我已经阅读了这个问题,但答案是使用宏,这不是很好: 模板c ++的模板?

我可以通过没有宏的模板来做到这一点吗?我正在使用Visual C++ 2013.

Pio*_*cki 12

UPDATE

引入了" P0127R2使用auto声明非类型模板参数 ",允许声明非类型模板参数auto作为实际类型的占位符:

template <auto P> struct Ptr {};
Run Code Online (Sandbox Code Playgroud)

也就是说,P是非类型模板参数.它的类型可以推断出来decltype(P).

auto在模板参数列表中受到众所周知的推论和部分排序规则的约束.在您的情况下,类型可以被约束为仅接受指针:

template <auto* P> struct Ptr {};
Run Code Online (Sandbox Code Playgroud)

请注意,auto即使是更详细的检查,语法利用也足够了,例如:

template <typename F>
struct FunctionBase;

template <typename R, typename... Args>
struct FunctionBase<R(*)(Args...)> {};

template <auto F>
struct Function : FunctionBase<decltype(F)> {};
Run Code Online (Sandbox Code Playgroud)

也可以使用推断类型作为其他模板参数的约束:

template <auto I, decltype(I)... Is>
struct List {};
Run Code Online (Sandbox Code Playgroud)

老答案

由于您在没有宏定义帮助的情况下询问基于纯类模板的解决方案,因此答案很简单:就目前而言(2014年12月,),这是不可能的.

这个问题已经被WG21 C++标准委员会确定为需要,并且有几个建议让模板自动推断非类型模板参数的类型.

最接近的是N3601隐式模板参数:

隐式模板参数

这个例子的目的是消除冗余template<typename T, T t>习语的需要.这个成语被广泛使用,在Google上点击量超过10万.

目标是能够替换模板声明,就像template<typename T, T t> struct C;使用另一个声明一样,这样我们就可以像模板一样即时发送模板,C<&X::f>而不必说C<decltype(&X::f), &X::f>.

基本的想法是能够template<using typename T, T t> struct C {/* ... */};表明T应该推断出来.为了更详细地描述,我们考虑了模板类和函数的一些扩展示例.

[...]

传递第二个模板参数类型的关键思想是冗余信息,因为它可以使用第二个类型参数的普通类型推导来推断.考虑到这一点,我们建议使用using前缀模板参数表明它不应该作为模板参数显式传递,而是从后续的非类型模板参数推导出来.这立即使我们能够提高describe_field如下的可用性.

template<using typename T, T t> struct describe_field { /* ... */ };
/* ... */
cout << describe_field<&A::f>::name;   // OK. T is void(A::*)(int)
cout << describe_field<&A::g>::arity;  // OK. T is double(A::*)(size_t)
Run Code Online (Sandbox Code Playgroud)

类似的提议是N3405模板花絮中包含的提议:

T两个

激励的例子是一个假定的反射类型特征,给出了一个类成员的属性.

struct A {
  void f(int i);
  double g(size_t s);
};
/* ... */
cout << describe<&A::f>::name;   // Prints "f"
cout << describe<&A::g>::arity;  // prints 1
Run Code Online (Sandbox Code Playgroud)

问题是"描述的声明应该什么样的?" 由于它采用非类型模板参数,我们需要使用熟悉的(在Google上点击100k)“template<class T, T t>”成语来指定参数的类型

template<typename T, T t> struct describe;
Run Code Online (Sandbox Code Playgroud)

[...]

我们的关键思想是传递第二个模板参数的类型(几乎总是)冗余信息,因为它可以使用来自第二个类型参数的普通类型推导来推断.考虑到这一点,我们建议允许describe声明如下.

template<typename T t> struct describe;
/* ... */
cout << describe<&A::f>::name;   // OK. T is void(A::*)(int)
cout << describe<&A::g>::arity;  // OK. T is double(A::*)(size_t)
Run Code Online (Sandbox Code Playgroud)

可以在EWG第9期跟踪这两个提案的当前状态.

还有一些其他讨论提出了替代语法auto:

template <auto T> struct describe;
Run Code Online (Sandbox Code Playgroud)