定义模板函数的最佳和最正确的方法是什么,其参数的类型必须是某个基类的子类?
这就是我所拥有的:
class A {};
class B : public A {};
class C {};
template <typename T>
int foo(T& x) // NB: need a solution that allows a return value
{
A& dummy = x; // require T to be a subclass of A, else SFINAE
return 1;
}
//int foo(C&) { return 2; }
int main()
{
B b;
C c;
std::cout << foo(b) << "\n";
std::cout << foo(c) << "\n"; // should fail unless foo(C&) is defined
}
以上是否正确?我不喜欢它,因为它没有表达意图。我更喜欢看起来更像下面的虚假代码:
template <class A T>
void foo(T& x) {}
也许enable_if
可以某种方式使用?
(背景:在我的生产代码中,函数是运算符。我需要它们作为元编程原因的模板(推导出T的编译时类型)。但是我想限制它们只匹配A的子类。)< / p>
更新#1:在Template Constraints C++的相关问题中,提供了以下内容:
static_assert(std::is_base_of<A, T>::value, "T must be a sublass of A");
这比A& dummy = x;
更好地捕获意图但是它遇到了同样的问题,如果void foo(C&) { }
被注释掉,foo<T>
仍然专门用于调用foo(c)
和然后static_assert
失败了。鉴于参数不是A的子类,我希望编译器甚至不尝试专门化foo<T>
。
更新#2:根据此处接受的答案:Why does enable_if_t in template arguments complains about redefinitions?以下代码似乎已关闭,但它是特定于C ++ 14的。我想要一个可以移植到当前标准的解决方案。
template <typename T, std::enable_if_t<std::is_base_of<A, T>::value>* = nullptr>
void foo(T& x)
{
}
上述优点是,当定义void foo(C&)
时,编译器会给出正确的错误:&#34;错误:没有用于调用&f; foo(C&amp;)&#39的匹配函数;&#34;
答案 0 :(得分:2)
取决于你真正想要的支票。
要检查公共的,明确的基础,请在指针上使用is_convertible
:
template <class T>
auto foo(T& x) -> std::enable_if_t<std::is_convertible<T*, A*>{}/*, void*/> {
// stuff
}
要检查任何基础,公共,受保护或隐私,含糊不清或明确,请使用is_base_of
:
template <class T>
auto foo(T& x) -> std::enable_if_t<std::is_base_of<A, T>{}/*, void*/> {
// stuff
}
答案 1 :(得分:0)
以下是另一种方法,基于T.C.的回答,以及这里接受的答案:(Why does enable_if_t in template arguments complains about redefinitions?):
#include <type_traits>
#include <iostream>
// Provide enable_if_t in C++11
#if __cplusplus <= 201103L
namespace std {
template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
}
#endif
class A {};
class B : public A {};
class C {};
template <typename T, std::enable_if_t<std::is_convertible<T*, A*>::value>* = nullptr>
int foo(T& x)
{
return 1;
}
//int foo(C& x) { return 2; }
int main()
{
B b;
C c;
std::cout << foo(b) << "\n";
std::cout << foo(c) << "\n"; // should fail unless foo(C&) is defined
}
当foo
未定义时,这会正确忽略模板int foo(C& x)
,因此会为foo(c)
行提供预期的(所需)编译器错误:
错误:没有匹配函数来调用'foo'