模板推导功能?

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)

但这意味着对于每个函数,我都必须编写另一个调用第一个函数的函数。真烦人。有更简单的方法吗?也许它可能是模板推论指南,但据我所知,对于函数,仅对类不存在。

编译器不能推断:因为模板推演失败的第一个模板的功能是不够CharTstd::basic_string<CharT>,从CharT const *。这就是为什么我需要一种更简单的方法来告诉编译器的原因。

dav*_*igh 6

经过更多的研究,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)

演示


bol*_*lov 5

只需咬一下子弹并使用2个重载即可。任何聪明的解决方案(如davidhigh所显示的那样确实存在)只会增加不必要的复杂性,潜在的错误以及对下一个读者的困惑。

您只写一次,但读多次。相对于非惯用的复杂智能方式,写1行身体超载的小麻烦是值得的。

别误会,我喜欢在C ++中找到这些智能解决方案,但是如果我在生产代码中找到了这个解决方案,那么我将花几分钟的时间来弄清楚它到底是什么以及它做什么,只是发现它只是以复杂的方式完成了本来应该是很基本的事情,所以我想……好吧,我只是说我不会对代码作者说些好话。编写代码时懒惰将使您花费更多的时间来维护,调试,扩展甚至使用代码。

编写简单,惯用且易于理解的代码!