如何修改以下函数模板,使其返回 42 如果模板参数T
和U
完全相同的类型?
template<typename T,typename U>
int Foo()
{
return 0;
}
使用std::is_same
可以提供所需的行为:
#include <type_traits>
template<typename T,typename U>
int Foo()
{
return std::is_same<T, U>::value ? 42 : 0;
}
一种惯用的方法是将工作委托给detail
命名空间中的辅助函数对象,您可以部分专门T
化与 相同的情况U
(或您可以在类模板中使用的任何其他编译时模式)。
namespace detail {
template<typename T, typename U>
struct foo
{
int operator()() const
{
return 0;
}
};
template<typename T>
struct foo<T, T>
{
int operator()() const
{
return 42;
}
};
} // namespace detail
template<typename T, typename U>
int Foo()
{
return detail::foo<T, U>()();
}
对于也具有可推导参数的函数(例如,a will Foo(T x, U y)
),这结合了函数模板的参数推导功能和类模板的专业化能力,而不需要用户都更聪明(好吧,你需要他们不调用任何东西的约定直接来自namespace detail
)
只是为了答案的完整性,以下是在没有类的情况下在编译时做出此选择的方法:
namespace detail
{
int Foo(std::true_type)
{
return 42;
}
int Foo(std::false_type)
{
return 0;
}
}
template <typename T, typename U>
int Foo()
{
return detail::Foo(std::is_same<T, U>());
}
当两个不同的代码路径对您的参数有不同的要求时(尽管在这种情况下没有要求),这种编译时分支很重要。例如,在一个路径中使用成员函数x()
,而在另一个路径中y()
;或者正如您所指出的,甚至是完全“不同”的功能。
对我来说,这比管理班级要简单得多。
那这个呢?
#include <iostream>
template<typename T,typename U>
struct Foo {
int operator()()
{
return 0;
}
};
template<typename T>
struct Foo<T, T> {
int operator()()
{
return 42;
}
};
int main() {
std::cout << Foo<int, int>()() << std::endl;
std::cout << Foo<int, double>()() << std::endl;
}