Fre*_*ios 4 c++ templates argument-deduction c++17
我正在尝试编写一些模板函数,它们接受可以构造的a std::basic_string或char数组basic_string。
我当前的解决方案是:
#include <string>
template<typename CharT>
void foo(std::basic_string<CharT> str)
{
(void)str; // do something with str
}
template<typename CharT>
void foo(CharT const * arr)
{
return foo(std::basic_string<CharT>{arr});
}
int main(void)
{
foo("hello");
foo(std::string{ "hello" });
foo(L"hello");
foo(std::wstring{ L"hello" });
}
Run Code Online (Sandbox Code Playgroud)
但这意味着对于每个函数,我都必须编写另一个调用第一个函数的函数。真烦人。有更简单的方法吗?也许它可能是模板推论指南,但据我所知,对于函数,仅对类不存在。
编译器不能推断:因为模板推演失败的第一个模板的功能是不够CharT的std::basic_string<CharT>,从CharT const *。这就是为什么我需要一种更简单的方法来告诉编译器的原因。
经过更多的研究,imo 的最佳选择是使用 C++17 特性std::basic_string_view:
template<typename CharT>
void foo(std::basic_string_view<CharT> str)
{
(void)str; // do something with str ...
// while remembering that string_view does not own the string
}
Run Code Online (Sandbox Code Playgroud)
因此,如果您可以访问 C++17 编译器,请忘记下面的旧解释。
这里有两种情况需要考虑。第一种情况是您并不是真的想对基本字符串做一些特殊的事情,而是您只应用也可用于char-array 的方法(并且只想确保它被正确调用而不管参数如何)。在这种情况下,我只需使用通用模板参数:
template<typename string_type
/* possibly some SFINAE to allow/disallow certain types */>
auto foo(string_type s)
{
std::cout << s << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
第二种情况是您确实想对 char 数组不存在的字符串进行一些特殊操作。在这种情况下,您需要为 重载basic_string,但您可能只想编写一次,而不是为您使用的每个函数编写一次。这是以下string_invoker类尝试做的事情(但它仍然需要一些改进,只是在努力):
template<typename method>
struct string_invoker_impl
{
string_invoker_impl(method m) : m(m) {}
template<typename CharT>
auto operator()(std::basic_string<CharT> str) const
{
return m(str);
}
template<typename CharT>
auto operator()(CharT const * arr) const
{
return operator()(std::basic_string<CharT>{arr});
}
//possibly further methods for non-const array's, modification, etc.
method m;
};
auto string_invoker = [](auto m) { return string_invoker_impl<decltype(m)>{m}; };
auto foo_impl = [](auto str) {std::cout<< str <<std::endl; };
auto foo = string_invoker(foo_impl);
//you can merge the previous two calls also in a single one:
//auto foo = string_invoker( [](auto str) {std::cout<< str <<std::endl; });
int main(void)
{
foo("hello");
foo(std::string{ "hello" });
//foo(L"hello"); //need std::wcout, thus it fails with std::cout
//but it's no general problem, just overload your foo_impl function
//foo(std::wstring{ L"hello" });
}
Run Code Online (Sandbox Code Playgroud)
只需咬一下子弹并使用2个重载即可。任何聪明的解决方案(如davidhigh所显示的那样确实存在)只会增加不必要的复杂性,潜在的错误以及对下一个读者的困惑。
您只写一次,但读多次。相对于非惯用的复杂智能方式,写1行身体超载的小麻烦是值得的。
别误会,我喜欢在C ++中找到这些智能解决方案,但是如果我在生产代码中找到了这个解决方案,那么我将花几分钟的时间来弄清楚它到底是什么以及它做什么,只是发现它只是以复杂的方式完成了本来应该是很基本的事情,所以我想……好吧,我只是说我不会对代码作者说些好话。编写代码时懒惰将使您花费更多的时间来维护,调试,扩展甚至使用代码。
编写简单,惯用且易于理解的代码!