我想创建一个重载模板,它运行一个函数 Foo() 如果一个类包含它,否则它什么都不做。
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()" << std::endl;
// Modify u
}
};
class B
{
// Does not contain Foo()
};
我一直在尝试这样运行它
template <typename T, typename U>
decltype(std::declval<T>().Foo()) TriggerFoo(T* t, U& u)
{
t->Foo(u);
}
template <typename T, typename U>
void TriggerFoo(T* t, U& u)
{
std::cout << "Does not have Foo()" << std::endl;
}
int main()
{
A a;
B b;
U u; // Some type
TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()".
return 0;
}
目前,这两个类都传递给“没有 Foo()”实例化。它编译,但显然它不起作用,这很可能是因为我对 declval 的理解不够好。我也尝试过使用非模板函数,但它仍然不起作用。
任何帮助将不胜感激。
最佳答案
您的方法存在两个基本问题:
decltype(std::declval<T>().Foo())
这永远不会成功解决,因为有问题的 Foo()
总是带有一个参数。这部分应该是:
decltype(std::declval<T>().Foo(std::declval<U &>()))
但是现在你会遇到一个不同的问题:当类实现Foo()
时,模板解析会变得不明确。可以使用任何一个模板函数。
因此,您需要另一个间接级别和不同优先级的模板:
#include <iostream>
#include <type_traits>
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()" << std::endl;
// Modify u
}
};
class B
{
// Does not contain Foo()
};
template <typename T, typename U, typename Z=decltype(std::declval<T>().Foo(std::declval<U &>()))>
void DoTriggerFoo(T* t, U& u, int dummy)
{
t->Foo(u);
}
template <typename T, typename U>
void DoTriggerFoo(T* t, U& u, ...)
{
std::cout << "Does not have Foo()" << std::endl;
}
template <typename T, typename U>
void TriggerFoo(T *t, U &u)
{
DoTriggerFoo(t, u, 0);
}
class U {};
int main()
{
A a;
B b;
U u; // Some type
TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()".
return 0;
}
gcc 5.3 的结果:
$ ./t
Has Foo()
Does not have Foo()
附言:
std::declval<T &>().Foo(std::declval<U &>())
对于您的实际类(class),这可能会更好。
关于函数模板的 C++ Decltype,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35931350/