Stroustrup提供Can_copy template。它是如何工作的?
template<class T1, class T2> struct Can_copy {
static void constraints(T1 a, T2 b) { T2 c = a; b = a; }
Can_copy() { void(*p)(T1,T2) = constraints; }
};
特别是,为什么他需要行void(*p)(T1,T2) = constraints;
而不是空构造函数?编译器是否只允许生成特定模板实例用作优化的函数?
答案 0 :(得分:8)
这是因为生成的代码中不存在模板中未使用的成员函数,因此要检查约束,您必须在某处明确地调用constraints()
。
这样生成constraints()
的代码,因此在编译时检查约束(这是Can_copy
的目的)。
答案 1 :(得分:4)
C ++03§14.7.1p1:
除非已明确实例化(14.7.2)或显式专用(14.7.3)类模板特化,否则在需要完全定义的对象类型的上下文中引用特化时,将隐式实例化类模板特化。当类类型的完整性影响程序的语义时。类模板特化的隐式实例化会导致类成员函数,成员类,静态数据成员和成员模板的声明但不是定义或默认参数的隐式实例化; ...
因此,此代码无法实例化Can_copy :: constraints:
template<class T1, class T2>
struct Can_copy {
static void constraints(T1 a, T2 b) { T2 c = a; b = a; }
Can_copy() { /* note the change here */ }
};
template<class Container>
void draw_all(Container& c) {
typedef typename Container::value_type T;
Can_copy<T,Shape*>(); // accept containers of only Shape*s
}
但是,在原始代码中,当Can_copy的ctor被实例化时,因为它必须在使用时,它的主体(定义)也是如此,并且触发Can_copy :: constraints的实例化。
您可以反过来看到同样的问题,其中显式实例化为您提供了所有内容,甚至是您不想要的内容:
typedef std::list<int>::iterator Iter;
std::reverse_iterator<Iter> x; // Implicit instantiation; works.
template std::reverse_iterator<Iter>;
// Explicit instantiation; fails to instantiate op+ and other operators used
// for random access iterators from reverse_iterator.
答案 2 :(得分:3)
想要提供信息,而不是答案(不值得支持):
在C ++ 0x中,您将在标题<type_traits>
中为此提供改进的功能。
std::is_copy_constructible<T1>::value;
std::is_copy_assignable<T1>::value;
std::is_constructible<T1, T2>::value;
std::is_assignable<T1, T2>::value;
std::is_convertible<T1, T2>::value;
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3225.pdf
搜索“[meta]”。
答案 3 :(得分:2)
模板的使用与Can_copy<int, char>();
如果T1的实例无法复制到T2的实例,则代码b = a
根本不会编译。同样,如果无法使用T1实例初始化T2的实例,则代码T2 c = a;
将无法编译。
因此,如果T1
无法复制到T2
,则包含模板用法的行将无法编译。
整个构造产生(几乎)没有代码,并且很容易被优化器删除。