在C++17中,为什么类模板和函数模板的指针类型推导明显不一致
In C++17, why is pointer type deduction apparently inconsistent for class templates versus function templates?
如果我将下面代码中的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);
}
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);
}
成功:
#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);
}
template <typename Arg>
struct bar {
bar(Arg && arg) { f(std::forward<Arg>(arg)); }
};
和
template <typename Arg>
void bar(Arg && arg) { f(std::forward<Arg>(arg)); }
不是一回事。在函数bar
中,您有一个转发引用。这允许您接受左值(p
(或右值(p + 0
(。
有了结构体bar
,就不再有转发引用了。它不再是转发引用的原因是它不再是函数模板参数。当CCD_ 6未知时,CCD_。由于您的T
(Args
(是已知的(虽然不是真的,但它正在被推导,因此它可以是已知的(,这意味着它不再是转发参考。
这意味着您有一个对类模板类型的右值引用。这对来说效果很好
bar a(p + 0);
因为结果是临时int*
(int*&&
(,但是具有
bar b(p);
你有一个int*
(int*&
(,所以你不能将右值引用绑定到它。
如果你想让类的行为像函数一样,你需要像这样的东西
struct bar {
template <typename Arg>
bar(Arg && arg) { f(std::forward<Arg>(arg)); }
};
否则,如果你只需要接受左值和右值,你可以添加重载来处理
template <typename Arg>
struct bar {
bar(Arg & arg) { f(arg); }
bar(Arg && arg) { f(std::move(arg)); }
};
我不确定您在这里想要实现什么,但这里有一些方法可以获得一个有效的示例。给定:
#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); // Arg is deduced to be int*
bar<int*&> b(p); // Arg is explicitly int*&
}
或者,您可以为模板结构提供用户定义的推导指南(请参阅文档(:
template<typename Arg> bar(const Arg&) -> bar<Arg&>;
void foo()
{
int dummy;
int *p = &dummy;
bar a(p + 0); // Arg is deduced to be int*
bar b(p); // Arg is deduced to be int*&
}
请记住,如果您的结构有任何模板类型的成员,并且您希望能够用引用类型初始化该结构,则必须初始化这些成员:
template <typename Arg>
struct bar {
Arg member; // if Arg is int*& then member has type int*&
bar(Arg && arg) : member(arg) { f(std::forward<Arg>(arg)); }
};
或者,如果你不需要成员有引用类型,你可以这样做:
template <typename Arg>
struct bar {
std::remove_reference_t<Arg> member; // if Arg is int*& then member has type int*
bar(Arg && arg) { f(std::forward<Arg>(arg)); }
};
相关文章:
- 非类型指针和引用模板参数,以及在编译时如何/为什么解析它们.c++
- 如何访问在 c++ 中在类内声明的结构类型指针变量?
- (C )找到基本类型指针的儿童类型
- 表达式必须具有指向对象的指针类型(指针向量)
- 将子项复制构造到父类型指针中
- C 返回类型指针声明
- 调用虚拟函数而不通过类类型指针创建任何对象
- C++ 如何使用类类型指针制作向量
- 为什么基类型指针不能获取派生类对象的地址值?
- 如何在 C++ 中获取映射类型指针,映射
- 如何检查该类型的类型指针是正确对齐的
- 正在转换为短类型指针
- 指向任意类方法的模板非类型指针
- 如何通过强制转换类型指针将字符数组转换为uint16_t
- 指向shared_ptr的不透明类型 C 指针
- C++:从值类型指针强制转换为包含迭代器
- C/C++:访问给定类型指针的位置与访问另一类型指针的相同位置不同
- 比较类型指针
- 数据类型指针使用*(Datatype *)
- 如何打印c++中char类型指针的所有值