【问题标题】:c++ template parameter type inferencec++模板参数类型推断
【发布时间】:2015-02-06 23:08:37
【问题描述】:

我在 C++ 中有这样一个模板

template<typename T, T* P> struct Ptr {};

所以我可以这样使用它:

const int i = 0;
Ptr<int, &i> ptr;

Ptr<decltype(i), &i> ptr;

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

Ptr<&i> ptr;

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

如何声明我的模板来做到这一点?

我读过这个问题,但答案是使用宏,这不好: template of template c++?

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

【问题讨论】:

  • 也许你能解释一下你想要达到的目标是什么?
  • 我想这是不可能的;在声明Ptr&lt;int&gt; ptr;时至少需要指定int,然后你想给你的对象一个参数,这样你需要再次指定它:Ptr&lt;int, &amp;i&gt; ptr;或类似std::shared_ptr的东西:Ptr&lt;int&gt; ptr(&amp;i);
  • @JohnZwinck 我认为 petric 更多的是询问 OP 的目标是什么,即 为什么 他希望能够做到这一点。所讨论的问题似乎是一个奇怪的要解决的问题。
  • @petric 更具体地说,Ptr 结构可以有 T get() { return *P; }set(T value) { *P = value; } 等成员。
  • 这正是N3601 Implicit template parameter,尚不支持

标签: c++ templates type-inference inferred-type


【解决方案1】:

更新

引入了“P0127R2 Declaring non-type template parameters with auto”,允许用auto 作为实际类型的占位符来声明一个非类型模板参数:

template <auto P> struct Ptr {};

P是一个非类型模板参数。可以通过decltype(P)推断其类型。

模板参数列表中的auto 遵循众所周知的推导和偏序规则。在您的情况下,可以将类型限制为仅接受指针:

template <auto* P> struct Ptr {};

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

template <typename F>
struct FunctionBase;

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

template <auto F>
struct Function : FunctionBase<decltype(F)> {};

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

template <auto I, decltype(I)... Is>
struct List {};

旧答案

由于您询问的是基于纯类模板的解决方案,没有宏定义的帮助,那么答案很简单:就目前而言(2014 年 12 月,不可能

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

最近的是N3601 Implicit template parameters:

隐式模板参数

本示例的目的是消除对冗余template&lt;typename T, T t&gt; 成语的需要。这个成语被广泛使用,在 Google 上的点击量超过 10 万次。

目标是能够用另一个声明替换像template&lt;typename T, T t&gt; struct C; 这样的模板声明,这样我们就可以实例化像C&lt;&amp;X::f&gt; 这样的模板,而不必说C&lt;decltype(&amp;X::f), &amp;X::f&gt;

基本思想是能够说出template&lt;using typename T, T t&gt; 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)

N3405 Template Tidbits中包含一个类似的提案:

两个人的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

问题是“describe 的声明应该是什么样子?” 由于它需要一个非类型模板参数,我们需要使用熟悉的(100k hits on谷歌)“template&lt;class T, T t&gt;”成语

template<typename T, T t> struct describe;

[...]

我们的关键思想是传递第二个模板参数的类型是(几乎总是)冗余信息,因为可以使用第二个类型参数的普通类型推导来推断它。考虑到这一点,我们建议允许 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)

可以在EWG issue 9 下跟踪两个提案的当前状态。

还有一些其他discussions 提出了auto 的替代语法:

template <auto T> struct describe;

【讨论】:

    猜你喜欢
    • 2023-03-31
    • 1970-01-01
    • 2018-07-07
    • 2020-07-09
    • 2022-12-02
    • 2019-09-12
    • 1970-01-01
    • 2020-06-25
    • 1970-01-01
    相关资源
    最近更新 更多