【问题标题】:Select string template implicitly by passing const char*通过传递 const char* 隐式选择字符串模板
【发布时间】:2017-02-06 09:11:37
【问题描述】:

假设我有我的自定义字符串类:

class my_string : public std::string
{
    // ...
}

我想创建一个模板函数,默认情况下同时接受my_string

template <typename TString = my_string>
TString do_something(const TString& input)
{
    // ...
}

但是当我调用它时:

auto result = do_something("abcdef");

它调用(当然)do_something&lt;char[7]&gt;()。如何强制它调用do_something&lt;my_string&gt; 明确指定类型(即写do_something("abcdef"),而不是do_something&lt;my_string&gt;("abcdef"))?

【问题讨论】:

  • 注意:虽然只是一个例子,但永远不要从 std::string 派生!
  • 我只想为 const char[] 添加一个重载并将其转发给您要调用的函数。
  • 文字字符串后缀可能会有所帮助:"abcdef"soperator "" _my_s "abcdef"_my_s
  • 为什么是模板? my_string 是一个 std::string (因此 std::string 应该可以转换为 my_string)
  • @boris 假定堆分配和多态指针。 new std::stringdelete std::string 已经是反模式,像std::string 这样的堆分配管理器是代码异味。在智能指针和值语义包装器(又名现代 C++)的土地上,建议相对过时。智能指针可以存储它们的删除器,并且应该是创建对象的方式(不直接调用new),值语义包装器要么不调用删除,要么使用智能指针。

标签: c++ templates


【解决方案1】:

特别是“从字符串参数构造”。

template <typename TString = my_string,
typename std::enable_if<std::is_base_of<std::string, TString>::value>::type = nullptr>
TString do_something(const TString& input)
{
    // ...
}

template <typename ...Args,
typename std::enable_if<std::is_constructible<my_string, Args....>::value>::type = nullptr>
my_string do_something(Args&&... args)
{
    return do_something<my_string>({args});
}

【讨论】:

    【解决方案2】:

    你真的需要函数模板吗?简单的功能:

    my_string do_something(my_string const& input) { ... }
    

    解决您的用例。您可以传入 my_string 或字符串文字,甚至是 braced-init-list,一切正常。


    由于其他原因需要模板,您可以简单地为 const char 的数组提供重载:

    template <class TString>
    TString do_something(TString const&) { ... }
    
    template <size_t N>
    my_string do_something(const char (&arr)[N]) {
        return do_something(my_string{arr, N-1});
    }
    

    注意:没有理由为模板参数TString 提供默认值。没有办法有意义地使用该默认值。

    【讨论】:

    • 它返回my_string,我不希望在使用std::string的旧代码中。
    • 你真的想在这里引用数组吗?我认为const char[] 参数会更有用,因为您可以传递数组或指针。
    • @NathanOliver 我宁愿只捕获字符串文字。
    【解决方案3】:

    回复

    我想创建一个模板函数,默认情况下同时接受my_string

    #include <string>
    
    template< class Type >
    struct Explicit_t_ { using T = Type; };
    
    template< class Type >
    using Explicit_ = typename Explicit_t_<Type>::T;
    
    namespace my {
        struct String: std::string { using std::string::string; };
    }  // namespace my
    
    template< class Some_string >
    auto do_something( Explicit_<Some_string> const& )
        -> Some_string
    { return "Template func!"; }
    
    auto do_something( my::String const& )
        -> my::String
    { return "my::String!"; }
    
    #include <iostream>
    using namespace std;
    auto main()
        -> int
    {
        cout << do_something( "" ) << endl;       // Output "my::String!"
        cout << do_something<std::string>( "" ) << endl;
    }
    

    您可以让my::String 的重载只转发到函数模板,除非您想要更专业或不同的实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-22
      • 2011-04-15
      • 2018-09-01
      • 1970-01-01
      • 2014-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多