使用 SFINAE 检查函数 std::to_string 是否存在类型
Using SFINAE to check function std::to_string exists for a type
我想创建一个函数模板,该模板专门用于可能已应用于它们的类型std::to_string
,另一个用于我已为其定义mylib::to_string
的类,并让任何类型可能不会落入其他实现或专用化。
例:
// I only want this to be found if std::to_string exists for ItemType
template<typename ItemType>
void func(ItemType &i)
{
std::cout << std::to_string(i);
}
// I only want this to be found if mylib::to_string exists for ItemType
template<typename ItemType>
void func(ItemType &i)
{
std::cout << mylib::to_string(i);
}
// And finally, I'd like to be able to fall through to anything that has a << defined for streams
template<>
void func<MyClass>(MyClass &i)
{
std::cout << MySpecialConverterFunc(i);
}
我总是std::enable_if
语法有问题。您将如何将其添加到第一个模板中?
对于 SFINAE,您不需要专业化,而是需要过载。无论如何,这比处理专业化(那些有怪癖)更理智。SFINAE 是一种指导重载解决的机制,而不是用于选择函数模板的显式专用化。
至于支票本身,你真的不需要enable_if
。只是一点点表达SFINAE会做:
template<typename ItemType>
auto func(ItemType &i) -> decltype(std::to_string(i), void())
{
std::cout << std::to_string(i);
}
void func(MyClass &i)
{
std::cout << MySpecialConverterFunc(i);
}
在上面的代码中,decltype
应用于逗号表达式。左手边是std::to_string(i)
的,如果它的格式不正确,整个表达式的格式不正确,我们得到一个替换错误,使编译器丢弃该重载("不是错误"部分)。如果格式正确,则右侧是void()
文字,因此decltype
会按预期解析为void
。
当替换失败时,我们只剩下第二次重载,所以它被选中。无论如何,都会为这种情况选择它,因为如果签名相同,则在重载解析中始终支持非模板重载。但是,在其他情况下添加检查以更好地指导编译器本身并不是一个坏主意。
SFINAE 并使用 ADL 规则编写简单代码
您可以通过利用 ADL(参数相关查找)来避免使用 SFINAE。ADL指出:
如果函数和类型都在同一命名空间中声明,则在调用该函数时不必指定命名空间。
例如:
namespace foo
{
class MyClass {};
std::string to_string(MyClass const& x) {
return "[Element of MyClass]";
}
}
int main() {
foo::MyClass x;
std::cout << to_string(x); // This is legal because x is in namespace foo
}
如果在命名空间中为类型编写to_string
函数,则可以根据以下方面编写一次func
:
template<class T>
void func(T const& t) {
using std::to_string;
// This calls std::to_string if std::to_string is defined;
// Otherwise it uses ADL to find the correct to_string function
std::cout << to_string(t);
}
在此示例中,可以使用foo::MyClass
调用func
,因为有一个to_string
函数接受命名空间foo
中的MyClass
:
int main() {
func(10); // Prints 10;
func(3.1415); // Prints 3.1415
foo::MyClass x;
func(x); // Prints [Element of MyClass]
}
我不拥有的命名空间中的类型怎么办?
在这种情况下,我建议创建一个额外的命名空间并将to_string
函数粘贴在那里,然后将其添加为using
语句:
namespace textConvert {
// Because we use std::to_string here, it automatically gets included
// When we use textConvert::to_string
using std::to_string;
// Convert a vector
template<class T>
std::string to_string(std::vector<T> const& vect) {
using std::to_string;
std::string str = "[";
for(auto& elem : vect) {
str += to_string(elem);
str += ',';
}
str.back() = ']';
return str;
}
}
然后,我们可以更新func
以包含textConvert::to_string
,并且由于除了各种自定义转换功能外textConvert
还使用std::to_string
,因此两者都包含在内!
template<class T>
void func(T const& t) {
// This *also* automatically includes std::to_string
// Because we put using std::to_string inside textConvert
using textConvert::to_string;
std::cout << to_string(t);
}
- "std::string"是否将其字符作为签名字符在内部存储?
- std::string 是否仅适用于 c++ 中的'std::cin'
- std::move on std::string 是否保证 .c_str() 返回相同的结果
- 在这个C++代码中,std::string 是否可以替换为模板参数 T,如果是这样,Meyer 关于其性能成本的论点是否仍然适用?
- 检查map<string,string>是否包含另一个map<string,string>
- std::string是否对分配的内存进行重新计数?如何通过值传递和通过引用传递不同的std::string大小写
- map<string1, map<string2, map<string3, string> > > 是否比将字符串连接到 map<string1string
- 使用 c_str() 返回的指针删除动态分配的 std::string 是否会导致C++内存泄漏
- 有效地比较QString和std::string是否相等
- 检查 std::string 是否包含任何小写字符
- 确定std::string是否具有所有唯一字符[C++]
- 检查String是否包含字典文件中的单词的快速方法
- 检查string是否是有效的整数或小数(正负两种情况)
- std::string是否需要将其字符存储在连续的内存中?< / h1 >
- 检查string是否包含其他字符串元素
- std::atomic<std::string> 是否正常工作?
- std::revers(ed) std::string是否在开始处包含空字符?
- 如何检查std::string是否确实是整数
- 检查 std::string 是否只有空格的有效方法
- 按值返回std::string是否安全?