1. 默认模板参数
您的情况"C"可以通过默认模板参数轻松解决:
template<typename T, typename U = int>
U foo(T x) {
return x;
}
template<>
double foo<double, double>(double x) {
return x;
}
现在,
foo
可以像一个带有单个模板参数的函数一样使用:
auto a = foo(5)
auto b = foo(1.0)
auto c = foo<short>(5)
2. 类型映射
另一种方法相对比较丑陋,但是更具普适性。它要求您在一个地方枚举所有可能的返回类型,从而允许您选择任何一个返回类型,基于模板参数类型。这种解决方案的关键在于编译时类型映射。它可以使用成对、元组和tuple_element
来实现,但是让我们停留在最简单的实现上:
struct last_key{};
struct last_value{};
template<typename key, typename k = last_key, typename v = last_value, typename ...pairs>
struct type_map {
static_assert(sizeof...(pairs) % 2 == 0, "Last key does not have a value");
using type = typename std::conditional<std::is_same<key, k>::value,
v,
typename type_map<key, pairs...>::type>::type;
};
template<typename key>
struct type_map<key> {
using type = int;
};
对于给定的键类型,地图将“返回”值类型,如果未找到键,则返回int
。有了地图,让我们声明一个取决于单个模板参数的返回类型:
template<typename key>
using return_type = typename type_map<key, double, double>::type;
最后,你的示例案例“C”将再次通过仅声明
foo
来解决:
template<typename T>
auto foo(T x) -> return_type<T> {
return x;
}
但是如果你想的话,仍然可以添加具有不同行为的专业化,这将编译并正常工作:
// Specialization.
template<>
auto foo(double x) -> double {
return x;
}
现在无论是否进行专业化,以下代码都是适用的:
auto a = foo(1);
auto b = foo(1.0);
std::cout << std::is_same<decltype(a), int>::value << std::endl;
std::cout << std::is_same<decltype(b), double>::value << std::endl;
将打印
1
1
T
作为返回类型,你期望什么?模板并不能完全打破语法规则。 - πάντα ῥεῖdouble foo(double x);
- Jarod42