我有一堆重载函数可以处理某些数据类型,例如int,double和strings。这些函数中的大多数执行相同的操作,其中仅允许一组特定的数据类型。这意味着我无法创建一个简单的通用模板函数,因为我失去了类型安全性(并且可能会导致函数内的验证运行时问题)。
是否可以创建“半通用编译时类型安全功能”?如果是这样,怎么样?如果没有,这是否会出现在C ++ 0x中?
一个(无效的)想法;
template <typename T, restrict: int, std::string >
void foo(T bar);
...
foo((int)0); // OK
foo((std::string)"foobar"); // OK
foo((double)0.0); // Compile Error
注意:我意识到我可以创建一个具有重载构造函数和赋值运算符的类,并将该类的变量传递给函数。
答案 0 :(得分:5)
使用sfinae
template<typename> struct restrict { };
template<> struct restrict<string> { typedef void type; };
template<> struct restrict<int> { typedef void type; };
template <typename T>
typename restrict<T>::type foo(T bar);
foo
只能接受string
的{{1}}或int
。如果调用T
,则不会发生硬编译时错误,而是如果有另一个接受该参数的函数,则会改为使用该函数。
答案 1 :(得分:1)
你可以创建一个永远不会暴露在外面的“私人”模板化功能,并从你的“安全”重载中调用它。
顺便说一句,通常直接暴露模板化版本存在问题:如果传递的类型不合适,将发出编译错误(除非您知道您的算法可能会暴露某些数据类型的细微错误)
答案 2 :(得分:0)
也许有点丑陋的解决方案,但是仿函数可能是一个选择:
class foo {
void operator()(double); // disable double type
public:
template<typename T>
void operator ()(T bar) {
// do something
}
};
void test() {
foo()(3); // compiles
foo()(2.3); // error
}
编辑:我反转我的解决方案
class foo {
template<typename T>
void operator ()(T bar, void* dummy) {
// do something
}
public:
// `int` is allowed
void operator ()(int i) {
operator ()(i, 0);
}
};
foo()(2.3); // unfortunately, compiles
foo()(3); // compiles
foo()("hi"); // error
答案 3 :(得分:0)
您可以使用要允许的“受限”类型的模板特化。对于所有其他类型,您不提供模板专门化,因此将使用通用的“基本”模板。你可以使用类似BOOST_STATIC_ASSERT的东西来抛出编译错误。
这里有一些伪代码来澄清我的想法:
template <typename T>
void foo(T bar) {BOOST_STATIC_ASSERT(FALSE);}
template<> // specialized for double
void foo(double bar) {do_something_useful(bar);};
答案 4 :(得分:0)
要列出任意类型的选择,我想您可以使用类型列表。请参阅last part of my earlier answer。
用法可能类似于:
//TODO: enhance typelist declarations to hide the recursiveness
typedef t_list<std::string, t_list<int> > good_for_foo;
template <class T>
typename boost::enable_if<in_type_list<T, good_for_foo> >::type foo(T t);