Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select string template implicitly by passing const char*

Tags:

c++

templates

Suppose I have my custom string class:

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

And I want to make a templated function which accepts both with my_string by default:

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

But when I call it with:

auto result = do_something("abcdef");

It calls (of course) do_something<char[7]>(). How to force it to call do_something<my_string> without explicitly specifying the type (i.e. write do_something("abcdef"), not do_something<my_string>("abcdef")) ?

like image 918
vladon Avatar asked Sep 28 '16 11:09

vladon


3 Answers

Particularize for "construct from string arguments".

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});
}
like image 189
utnapistim Avatar answered Nov 05 '22 18:11

utnapistim


Do you really need a function template? The simple function:

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

solves your use-case. You can pass in a my_string or string literal, or even a braced-init-list and everything just works.


Since you need a template for other reasons, you can simply provide an overload for arrays of 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});
}

Note: there's no reason to provide a default for the template parameter TString. There's no way for that default to be meaningfully used.

like image 45
Barry Avatar answered Nov 05 '22 17:11

Barry


Re

I want to make a templated function which accepts both with my_string by default

#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;
}

You can let the overload for my::String just forward to the function template, unless you want a more specialized or different implementation.

like image 1
Cheers and hth. - Alf Avatar answered Nov 05 '22 19:11

Cheers and hth. - Alf