我正在尝试使用模板专门化和隐式转换的组合,将模板类型分为3类:
- 可以隐式转换为字符串的类型 可以隐式转换为double类型的
- 类型不能隐式转换为字符串或双精度
然而,在我的这个尝试中,所有可以转换为双精度类型或字符串的类型最终都以t类型的默认情况结束。
template<>
void Foo(std::string s)
{
//can be converted to a string
}
template<>
void Foo(double d)
{
//can be converted to a double
}
template<typename T>
void Foo(T t)
{
//cannot be converted to a string or a double
}
struct Other {};
int main()
{
Foo("bar");// creates Foo(const char*) instead of converting to string
Foo(1);// creates Foo(int) instead of converting to double
Other o
Foo(o);// creates Foo(Other)
}
另一方面,如果模板被删除,隐式转换可以工作,但代价是无法处理"neither";类型。
void Foo(std::string s)
{
//can be converted to a string
}
void Foo(double d)
{
//can be converted to a double
}
struct Other {};
int main()
{
Foo("bar");// const char* -> std::string
Foo(1);// int -> double
Other o
Foo(o);// No overload available for this type
}
在创建新的模板化函数之前,是否有一种方法可以优先考虑隐式转换到现有的专用模板?或者也许我应该用完全不同的方式来解决这个问题?不要专门化…老实说,如果问题X与解决方案Y有关,那么专门化函数模板几乎总是z。对于要调用的专门化,推导出的模板参数必须是正好是我们专门化的。而且,在重载解析中甚至不考虑专门化是否存在。! 重载仅从主模板声明中解析。
对于您的问题,您需要重载,以便在重载解析中始终考虑这两个自定义用例。然后,您只需要确保在需要时简单地丢弃一般的catch-call函数。SFINAE,以及一些标准类型特征将完全实现这一目标。
#include <type_traits>
// Overloads. Not templates!
void Foo(std::string s)
{
//can be converted to a string
}
void Foo(double d)
{
//can be converted to a double
}
template<typename T>
std::enable_if_t<!(std::is_convertible_v<T, std::string> || std::is_convertible_v<T, double>)>
Foo(T t)
{
//cannot be converted to a string or a double
}
看条件是怎样的正是你想要检查的?类型特征验证转换是否可能,在这种情况下,std::enable_if_t
是一个病态类型(不存在)。因此重载被简单地丢弃(因为SF 我ailureN sotE n)。其他两个重载仍然存在,所以其中一个被选中。
如果两个转换都不可能,则模板重载不会被丢弃,并且函数的返回类型std::enable_if_t
为void (void
是enable_if_t
默认解析的类型)。
如果你有新的编译器支持最新的c++标准,你甚至可以用一种比经典的SFINAE更友好的方式来编写它
#include <concepts>
template<typename T>
requires !(std::convertible_to<T, std::string> || std::convertible_to<T, double>)
void Foo(T t)
{
//cannot be converted to a string or a double
}
约束现在可以在声明中占据自己的位置,将返回类型排除在魔术之外。