Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么不从构造函数中推断模板参数?_C++_Templates_Parameters_Inference - Fatal编程技术网

C++ 为什么不从构造函数中推断模板参数?

C++ 为什么不从构造函数中推断模板参数?,c++,templates,parameters,inference,C++,Templates,Parameters,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 Vari

我今天的问题很简单:为什么编译器不能从类构造函数推断模板参数,就像它可以从函数参数推断一样?例如,为什么以下代码无效:

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
}
模板
类变量{
obj数据;
公众:
变量(objd){data=d;}
};
int main(){
int num=2;
变量var(num);//将等效于变量var(num),
返回0;//但实际上是一个编译错误
}

正如我所说,我明白这是无效的,所以我的问题是为什么不是?允许这样做会造成任何重大的语法漏洞吗?是否存在不需要此功能的实例(推断类型会导致问题)?我只是想理解允许对函数进行模板推理背后的逻辑,但不允许对适当构造的类进行模板推理。

你是对的,编译器可以很容易地猜到,但据我所知,它不在标准或C++0x中,因此你必须再等待至少10年(ISO标准固定周转率)在编译器提供程序添加此功能之前

使ctor成为模板,变量只能有一种形式,但有多种ctor:

class Variable {
      obj data; // let the compiler guess
      public:
      template<typename obj>
      Variable(obj d)
       {
           data = d;
       }
};

int main()
{
    int num = 2;
    Variable var(num);  // Variable::data int?

    float num2 = 2.0f;
    Variable var2(num2);  // Variable::data float?
    return 0;         
}
类变量{
obj data;//让编译器猜测
公众:
模板
变量(obj d)
{
数据=d;
}
};
int main()
{
int num=2;
变量var(num);//变量::数据int?
浮动num2=2.0f;
变量var2(num2);//变量::数据浮点?
返回0;
}

看到了吗?我们不能有多个Variable::data成员。

请参阅以获取更多信息。

我认为这是无效的,因为构造函数并不总是类的唯一入口点(我说的是copy constructor和operator=)

MyClass m(string s);
MyClass *pm;
*pm = m;
我不确定解析器是否会如此明显地知道MyClass pm的模板类型

不确定我说的是否有意义,但请随意添加一些评论,这是一个有趣的问题

C++ 17 可以接受的是,C++17将从构造函数参数中进行类型推断

示例:

std::pair p(2, 4.5);
std::tuple t(4, 3, 2.5);

许多类不依赖于构造函数参数。只有少数几个类只有一个构造函数,并基于该构造函数的类型进行参数化

如果确实需要模板推断,请使用帮助器函数:

template<typename obj>
class Variable 
{
      obj data;
public: 
      Variable(obj d)
      : data(d)
      { }
};

template<typename obj>
inline Variable<obj> makeVariable(const obj& d)
{
    return Variable<obj>(d);
}
模板
类变量
{
obj数据;
公众:
变量(obj d)
:数据(d)
{ }
};
模板
内联变量makeVariable(const obj&d)
{
返回变量(d);
}

假设编译器支持您的请求。那么这个代码是有效的:

Variable v1( 10); // Variable<int>

// Some code here

Variable v2( 20.4); // Variable<double>

编译器应该做什么?使用泛型变量类定义来推断它是变量,然后发现变量没有提供一个参数构造函数?

让我们看看每个人都应该熟悉的类的问题-std::vector

首先,vector的一个非常常见的用法是使用不带参数的构造函数:

vector <int> v;
我们得到的是整数的向量,而不是字符串,大概它没有大小

最后,考虑构造多个参数的构造函数:“推断”:

应该使用哪个参数进行推断?我们需要某种方式告诉编译器它应该是第二个


一类简单的向量,不难理解推理的原因。

类型的推导仅限于当前C++中的模板函数,但长期以来一直被认为在其他上下文中的类型推导是非常有用的。因此C++0x的

auto

虽然您的建议在C++0x中是不可能实现的,但以下内容表明您可以非常接近:

template <class X>
Variable<typename std::remove_reference<X>::type> MakeVariable(X&& x)
{
    // remove reference required for the case that x is an lvalue
    return Variable<typename std::remove_reference<X>::type>(std::forward(x));
}

void test()
{
    auto v = MakeVariable(2); // v is of type Variable<int>
}
模板
变量MakeVariable(X&&X)
{
//删除x为左值时所需的引用
返回变量(std::forward(x));
}
无效测试()
{
auto v=MakeVariable(2);//v是变量类型
}

仍然缺失:这使得以下代码非常模糊:

int main()
{
    int num = 2;
    Variable var(num);  // If equivalent to Variable<int> var(num),
    Variable var2(var); //Variable<int> or Variable<Variable<int>> ?
}
intmain()
{
int num=2;
变量var(num);//如果等价于变量var(num),
变量var2(var);//变量还是变量?
}

由于其他人提出的原因,您不能按要求行事,但您可以这样做:

template<typename T>
class Variable {
    public: Variable(T d) {}
};
template<typename T>
Variable<T> make_variable(T instance) {
  return Variable<T>(instance);
}

C++03和C++11标准不允许从传递给constructor的参数中推断模板参数

但是有一个“构造函数模板参数推断”的建议,所以您可能很快就会得到您想要的编辑:事实上,C++17已经确认了此功能。


请参阅:

在2016年的开明时代,自从有人提出这个问题以来,我们制定了两个新标准,而且一个新标准即将出台,关键是要知道支持C++17标准的编译器将

C++17中类模板的模板参数推导 (由Olzhas Zhumabek编辑的接受答案提供)是详细说明标准相关变更的文件

解决来自其他答案的担忧 当前最高评级的答案 这个答案指出,“复制构造函数和
操作符=
”不知道正确的模板专门化

这是胡说八道,因为标准的复制构造函数和
运算符=
只存在于已知的模板类型中:

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;
在这里,
pm
已经是正确的类型,因此推断很简单。此外,调用复制构造函数时不可能意外地混合类型:

MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
此处,
pm
将是指向
m
副本的指针。在这里,
MyClass
是从
m
复制而来的,它的类型是
MyClass
(而不是不存在的类型
MyClass
)。因此,在推断出pm的类型时,有足够的信息
template <class X>
Variable<typename std::remove_reference<X>::type> MakeVariable(X&& x)
{
    // remove reference required for the case that x is an lvalue
    return Variable<typename std::remove_reference<X>::type>(std::forward(x));
}

void test()
{
    auto v = MakeVariable(2); // v is of type Variable<int>
}
int main()
{
    int num = 2;
    Variable var(num);  // If equivalent to Variable<int> var(num),
    Variable var2(var); //Variable<int> or Variable<Variable<int>> ?
}
template<typename T>
class Variable {
    public: Variable(T d) {}
};
template<typename T>
Variable<T> make_variable(T instance) {
  return Variable<T>(instance);
}
auto v = make_variable(instance);
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;
MyClass m(string("blah blah blah"));
decltype(m) *pm;               // uses type inference!
*pm = m;
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
MyClass(const MyClass&);
template <typename T> foo();
foo();
Variable var(num);  // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
Variable var(num);          // infering ctor
Variable var2(var);         // copy ctor
Variable var3(move(var));   // move ctor
// Variable var4(Variable(num));     // compiler error