如何将类型名称T
限制为特定类型?
考虑一下:
template <typename T>
struct Worker {
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
这就是我通常最终要做的事情:
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0;}
}
struct WorkabelTypeA : WorkableType {
std::string toString() { return "A"; }
int get() { return 1;}
};
//Similarly
struct WorkableTypeB : WorkableType;
并使用静态断言和std::is_base_of
:
template <typename T>
struct Worker {
static_assert(std::is_base_of<WorkableType, T>::value, "Needs workable type");
// Do something with T
};
是否有其他设计模式,更多C ++方式限制意外实例化错误的类型模板?
编辑:当C ++ Concepts成为标准时,似乎可以更好地解决这个问题。在那之前我想,static_assert可能比enable_if更清晰,更冗长。
答案 0 :(得分:2)
您可以使用SFINAE和模板专业化:
// type trait that evaluates always to false to use in the primary template
template<typename ... T> struct always_false : std::false_type { };
// primary template
template<typename T, typename Enable = void>
struct Worker {
static_assert(always_false<T, Enable>::value, "Needs workable type");
};
// specialisation
template<typename T>
struct Worker<T, std::enable_if_t<std::is_base_of<WorkableType, T>::value>> {
...
};
答案 1 :(得分:1)
您可以在类中创建特征并检查它,因此,不需要继承。例如:
template <typename T>
using toString_t = decltype(std::declval<T>().toString());
template <typename T>
using get_t = decltype(std::declval<T>().get());
// Use C++17, but can be done in C++11
template <typename T>
using has_toString = std::is_detected<toString_t, T>;
template <typename T>
using has_get = std::is_detected<get_t, T>;
然后
template <typename T>
struct Worker {
static_assert(has_toString<T>::value, "T should have toString");
static_assert(has_get<T>::value, "T should have get");
};
答案 2 :(得分:1)
如果你确切地知道你想要允许哪些类型,那么traits类就是一种简洁的方法:
#include <utility>
// by default nothing is workable
template<class T>
struct is_workable : std::false_type
{
};
template <typename T>
struct Worker {
static_assert(is_workable<T>(), "not a workable type");
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
// define a worker
struct A {};
// make it workable
template<> struct is_workable<A> : std::true_type {};
// define another worker but forget to make it workable
struct B {};
int main()
{
Worker<A> wa{};
// Worker<B> wb{}; // compile error - not workable
};
答案 3 :(得分:0)
您可以使用以下专业化:
#include<string>
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0; }
};
struct A {};
struct B {};
template<typename> struct Worker;
template<> struct Worker<A>: WorkableType {};
int main() {
Worker<A> wa;
// this won't compile
// Worker<B> wb;
}