为什么我不能用上面的构造函数实例化一个Foo类型的对象?
我有一个使用内部typedef的类Bar(作为“template typedefs”的解决方法),并打算在构造函数中使用它,如下所示(CASE 1)。 但是,我似乎没有得到它编译。这是合法的C ++吗? 案例2似乎表明问题与Bar中的typedef有关。
如何定义一个构造函数来接受具有Bar?
类型的对象的std :: vectors#include <vector>
#include <iostream>
#include <utility>
template <typename T>
struct Bar
{
typedef std::pair<T, T> type; // or anything else that uses T
};
struct Foo
{
Foo() {}
// CASE 1: doesn't compile
template <typename T> explicit Foo( const std::vector<typename Bar<T>::type>& data )
{
std::cout << "Hello\n";
}
//// CASE 2: compiles, but it's not what I want
//template <typename T> explicit Foo( const std::vector<Bar<T> >& data )
//{
// std::cout << "Hello\n";
//}
};
int main()
{
std::vector<Bar<int>::type> v; // for CASE 1
//std::vector<Bar<int> > v; // for CASE 2
Foo f( v );
return 0;
}
答案 0 :(得分:9)
根据C ++标准的第14.8.2.1段,当模板参数仅用于非推导的上下文时,不能推导出相应的模板参数:
如果 template-parameter 未在函数模板的任何函数参数中使用,或仅在非推导的上下文中使用,则其对应的 template-argument 无法从函数调用推断出,并且必须明确指定 template-argument 。
非受限上下文的定义,如§14.8.2.4中所述:
非弱势语境是:
使用 qualified-id 指定的类型的嵌套名称说明符。
一个 template-id 的类型,其中一个或多个 template-arguments 是一个引用模板参数的表达式
在Bar<T>::type
中,Bar<T>
是嵌套名称说明符,因此是非推断的上下文,因此在调用构造函数时必须显式指定模板参数。 ..这是不可能的(即你不能写Foo f<int>(v)
)。
我认为编译器不能推导出模板参数,因为这至少是麻烦的,而且可能是不可能的:想象Bar是专门的:
template<typename T>
struct Bar
{
typedef std::pair<T,T> type;
};
template<>
struct Bar<char>
{
typedef std::pair<int,int> type;
};
现在,在使用std::vector<std::pair<int,int> >
调用Foo的构造函数时,我有一个歧义:模板参数应该是int
还是char
?即使没有这种歧义,你也可以很容易地看到编译器在使用正确的typedef找到实例化之前必须实例化任何类型的Bar(好吧,我不太确定上面的语句是真正相关的,因为我经常找出编译器比我想象的要聪明得多: - )!)
答案 1 :(得分:4)
你的构造函数是:
template <typename T>
explicit
Foo( const std::vector<typename Bar<T>::type>& data )
模板参数T
不能以这种方式从函数参数中推导出来。 (我认为这被称为“不可推翻的背景”,但我不确定。)
这根本行不通。你必须写
template <typename B>
explicit
Foo( const std::vector<B>& data )
而是找到其他方法断言B
的类型为typename Bar<T>::type
。
答案 2 :(得分:0)
我认为唯一的原因是你想要实例化相应类型的Bar而不是打印“hello”。
也许您可以尝试以相反的方向映射类型(您希望编译器能够执行的反向推导类型):
#include <utility>
#include <vector>
template <class T>
struct BarType;
template <class T>
struct BarType<std::pair<T, T> >
{
typedef T type;
};
template <class T>
struct Bar {};
struct Foo
{
template <class T>
Foo(const std::vector<T>& )
{
Bar<typename BarType<T>::type> bar;
//...
}
};
int main()
{
Foo(std::vector<std::pair<int, int> >());
}
答案 3 :(得分:0)
这样的事情能为你效劳吗?
#include <vector>
#include <iostream>
#include <utility>
#include <boost/static_assert.hpp>
template <typename T>
struct Bar
{
typedef std::pair<T, T> type; // or anything else that uses T
enum {val = 42};
};
template <typename T>
struct Traits
{
enum {allowed = false};
};
template <typename T>
struct Traits<std::pair<T, T> >
{
enum {allowed = true};
typedef Bar<T> BarType;
};
struct Foo
{
Foo() {}
template <typename T> explicit Foo( const std::vector<T>& data )
{
BOOST_STATIC_ASSERT(Traits<T>::allowed);
typedef typename Traits<T>::BarType BarType;
std::cout << BarType::val << std::endl;
}
};
int main()
{
std::vector<Bar<int>::type> v;
std::vector<float> v2;
Foo f( v );
// Foo f2( v2 ); // Compile error
return 0;
}
这在GCC 4.4.1上编译并运行。您可以将Traits
专门用于构造函数允许的其他vector::value_type
。