在C++ 17中,为什么指针类型推导显然与类模板和函数模板不一致?

Wal*_*ltK 1 c++ lvalue rvalue-reference perfect-forwarding c++17

如果我将下面代码中的CLASS更改为0而不是1,它将使用gcc或clang进行编译.但是如果CLASS为1,则两个编译器都会失败(在第二次使用bar时).

#define CLASS 1

#include <utility>

void f(int *a);

template <typename Arg>
#if CLASS
struct bar {
#else
void
#endif

bar(Arg && arg) { f(std::forward<Arg>(arg)); }

#if CLASS
};
#endif

void foo()
{
  int dummy;
  int *p = &dummy;

  #if !CLASS
    #define a
    #define b
  #endif

  bar a(p + 0);
  bar b(p);
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/g/3hpq2u

作为两个单独的片段,没有条件编译:

失败:

#include <utility>

void f(int *a);

template <typename Arg>
struct bar {    
    bar(Arg && arg) { f(std::forward<Arg>(arg)); }
};

void foo()
{
  int dummy;
  int *p = &dummy;

  bar a(p + 0);
  bar b(p);
}
Run Code Online (Sandbox Code Playgroud)

成功:

#include <utility>

void f(int *a);

template <typename Arg>
void bar(Arg && arg) { f(std::forward<Arg>(arg)); }

void foo()
{
  int dummy;
  int *p = &dummy;

  bar(p + 0);
  bar(p);
}
Run Code Online (Sandbox Code Playgroud)

Nat*_*ica 8

template <typename Arg>
struct bar {
    bar(Arg && arg) { f(std::forward<Arg>(arg)); }
};
Run Code Online (Sandbox Code Playgroud)

template <typename Arg>
void bar(Arg && arg) { f(std::forward<Arg>(arg)); }
Run Code Online (Sandbox Code Playgroud)

不是一回事.在该功能中,bar您有转发参考.这允许您接受左值(p)或右值(p + 0).

使用结构,bar您不再具有转发引用.它不再是转发引用的原因是因为它不再是函数模板参数. 不知道T&&时只是转发参考T.由于你的T(Args)已知(但不是真的,但它被推断,因此可以知道),这意味着它不再是转发参考.

这意味着你有一个对类模板类型的rvalue引用.这很适合

bar a(p + 0);
Run Code Online (Sandbox Code Playgroud)

因为结果是临时int*(int*&&)但是有

bar b(p);
Run Code Online (Sandbox Code Playgroud)

你有一个int*(int*&)所以你不能将rvalue-reference绑定到那个.


如果你希望类的行为像函数一样,你需要类似的东西

struct bar {
    template <typename Arg>
    bar(Arg && arg) { f(std::forward<Arg>(arg)); }
};
Run Code Online (Sandbox Code Playgroud)

否则,如果你只需要接受左值和右值,你可以添加重载来处理它

template <typename Arg>
struct bar {
    bar(Arg & arg) { f(arg); }
    bar(Arg && arg) { f(std::move(arg)); }
};  
Run Code Online (Sandbox Code Playgroud)