GRB*_*GRB 101 c++ parameters templates inference
今天我的问题很简单:为什么编译器不能从类构造函数中推断模板参数,就像它可以从函数参数那样做?例如,为什么以下代码无效:
template<typename obj>
class Variable {
obj data;
public: Variable(obj d)
{
data = d;
}
};
int main()
{
int num = 2;
Variable var(num); //would be equivalent to Variable<int> var(num),
return 0; //but actually a compile error
}
Run Code Online (Sandbox Code Playgroud)
正如我所说,我明白这是无效的,所以我的问题是为什么不是呢?允许这会产生任何重大的句法漏洞吗?是否存在不希望使用此功能的实例(推断类型会导致问题)?我只是想了解允许函数的模板推理背后的逻辑,但不适用于适当构造的类.
Dra*_*kar 45
我认为这是无效的,因为构造函数并不总是类的唯一入口点(我在谈论复制构造函数和operator =).所以假设你正在使用这样的类:
MyClass m(string s);
MyClass *pm;
*pm = m;
Run Code Online (Sandbox Code Playgroud)
我不确定解析器是否会明白哪个模板类型是MyClass pm;
不确定我说的是否有意义,但随意添加一些评论,这是一个有趣的问题.
可以接受的是,C++ 17将从构造函数参数中进行类型推导.
例子:
std::pair p(2, 4.5);
std::tuple t(4, 3, 2.5);
Run Code Online (Sandbox Code Playgroud)
接受的纸.
小智 26
由于其他人已经解决的原因,你不能按照你的要求去做,但你可以这样做:
template<typename T>
class Variable {
public: Variable(T d) {}
};
template<typename T>
Variable<T> make_variable(T instance) {
return Variable<T>(instance);
}
Run Code Online (Sandbox Code Playgroud)
出于所有意图和目的,你要求的是同一件事.如果你喜欢封装,你可以使make_variable成为静态成员函数.这就是人们称之为命名构造函数的东西.因此,它不仅可以满足您的需求,而且几乎可以满足您的需求:编译器从(命名)构造函数中推断出模板参数.
注意:任何合理的编译器都会在你写这样的东西时优化掉临时对象
Variable<T> v = make_variable(instance);
Run Code Online (Sandbox Code Playgroud)
Kyl*_*and 20
在2016年的开明时代,自从提出这个问题以来,我们已经提出了两个新标准,而新的标准即将到来,重要的是要知道支持C++ 17标准的编译器将按原样编译您的代码..
这里(由Olzhas Zhumabek编辑接受的答案提供)是详细说明标准相关变更的文件.
这个答案指出"复制构造函数operator="并不知道正确的模板特化.
这是无稽之谈,因为标准的复制构造函数operator= 只存在于已知的模板类型中:
template <typename T>
class MyClass {
MyClass(const MyClass&) =default;
... etc...
};
// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm; // WHAT IS THIS?
*pm = m;
Run Code Online (Sandbox Code Playgroud)
在这里,我在评论中指出,没有任何理由对MyClass *pm不符合或不推论的新形式的法律声明:MyClass 不是一个类型(这是一个模板),所以它没有任何意义申报的指针类型MyClass.以下是修复示例的一种可能方法:
MyClass m(string("blah blah blah"));
decltype(m) *pm; // uses type inference!
*pm = m;
Run Code Online (Sandbox Code Playgroud)
这里,pm是已经正确的类型,所以推断是微不足道的.而且,在调用copy-constructor时不可能意外地混合类型:
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
Run Code Online (Sandbox Code Playgroud)
这里,pm将是一个指向副本的指针m.这里MyClass是从m-which类型MyClass<string>(而不是不存在类型MyClass)复制构造的.因此,在点pm的类型推断,存在是足够的信息来知道模板型的m,因此,模板型的pm,是string.
此外,以下将始终 引发编译错误:
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
Run Code Online (Sandbox Code Playgroud)
这是因为复制构造函数的声明不是模板化的:
MyClass(const MyClass&);
Run Code Online (Sandbox Code Playgroud)
这里,copy-constructor参数的template-type 匹配整个类的模板类型; 即,当MyClass<string>实例化时,MyClass<string>::MyClass(const MyClass<string>&);用它实例化,并且当MyClass<int>实例化时,MyClass<int>::MyClass(const MyClass<int>&);实例化.除非明确指定或声明了模板化构造函数,否则编译器没有理由进行实例化MyClass<int>::MyClass(const MyClass<string>&);,这显然是不合适的.
Pitiş给出了一个例子推导Variable<int>和Variable<double>,然后说:
我在代码中有两个不同类型(变量和变量)的相同类型名称(变量).从我的主观角度来看,它几乎影响了代码的可读性.
如前面的示例所述,Variable它本身不是类型名称,即使新功能使其在语法上看起来像一个.
然后Pitiş询问如果没有给出允许适当推断的构造函数会发生什么.答案是不允许推理,因为推理是由构造函数调用触发的.没有构造函数调用,就没有推论.
这类似于询问foo此处推断的版本:
template <typename T> foo();
foo();
Run Code Online (Sandbox Code Playgroud)
答案是,由于上述原因,此代码是非法的.
据我所知,这是对提出的功能提出合理关注的唯一答案.
例子是:
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
Run Code Online (Sandbox Code Playgroud)
关键问题是,编译器是在这里选择类型推断的构造函数还是复制构造函数?
尝试编写代码,我们可以看到复制构造函数被选中.要扩展示例:
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
// Variable var4(Variable(num)); // compiler error
Run Code Online (Sandbox Code Playgroud)
我不确定该提案和该标准的新版本如何具体说明; 它似乎是由"演绎指南"决定的,这是我还不了解的一个新的标准.
我也不确定为什么var4扣除是非法的; 来自g ++的编译器错误似乎表明该语句被解析为函数声明.
MSa*_*ers 11
仍然缺少:它使以下代码非常模糊:
int main()
{
int num = 2;
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); //Variable<int> or Variable<Variable<int>> ?
}
Run Code Online (Sandbox Code Playgroud)
假设编译器支持您的要求.那么这段代码是有效的:
Variable v1( 10); // Variable<int>
// Some code here
Variable v2( 20.4); // Variable<double>
Run Code Online (Sandbox Code Playgroud)
现在,我在代码中有两个不同类型(变量和变量)的相同类型名称(变量).从我的主观角度来看,它几乎影响了代码的可读性.在同一命名空间中为两个不同类型设置相同的类型名称对我来说是误导性的.
稍后更新: 要考虑的另一件事:部分(或完整)模板专业化.
如果我专门使用Variable并且没有像你期望的那样提供构造函数怎么办?
所以我会:
template<>
class Variable<int>
{
// Provide default constructor only.
};
Run Code Online (Sandbox Code Playgroud)
然后我有代码:
Variable v( 10);
Run Code Online (Sandbox Code Playgroud)
编译器应该怎么做?使用泛型变量类定义推断它是变量,然后发现变量不提供一个参数构造函数?
C++ 03和C++ 11标准不允许从传递给constuructor的参数中扣除模板参数.
但是有一个建议"建筑师的模板参数扣除",所以你可能很快得到你要求的东西.编辑:事实上,这个功能已经被C++确认17.
见:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3602.html和http://www.open-std.org/jtc1/sc22/wg21/docs/论文/ 2015/p0091r0.html
| 归档时间: |
|
| 查看次数: |
16789 次 |
| 最近记录: |