2

I faced some situation where I have to write two functions, one of them should be invoked with primitive types and std::string. The other one should be called with other types.

So far I ended with working solution:

template <typename...>
struct Void_t_helper {
    using type = void;
};

template <typename... Ts>
using Void_t = typename Void_t_helper<Ts...>::type;


template <typename T, typename = void>
struct Is_string : std::false_type {};

template <typename T> 
struct Is_string<T, Void_t<decltype (std::declval<T> ().c_str ())>> : std::is_same<decltype (std::declval<T> ().c_str ()), const char*>::type {};


template <typename T>
std::enable_if_t<Is_string<T>::value || std::is_arithmetic<T>::value, void> foo (T) {
    std::cout << "string or primitive\n";
}

template <typename T>
std::enable_if_t<!Is_string<T>::value && !std::is_arithmetic<T>::value, void> foo (T) {
    std::cout << "other type\n";
}

And the usage:

foo (1);
foo (1.2);
foo (std::string {"fsdf"});
foo (std::vector<int> {1, 2, 3});
foo (std::vector<std::string> {"a", "v", "c"});

produces as expected:

string or primitive
string or primitive
string or primitive
other type
other type

My question is: Do you know better solution to this kind of problem?

I am not really sure if checking if c_str() exists is the better option I can get. I am aware that I could probably write some wrapper class that for primitive types and std::string would have some category_t defined with value X, and for other types value Y and distinguish between these groups using this category, but still I think that c_str() checking is more convenient.

Artur Pyszczuk
  • 1,920
  • 1
  • 16
  • 23
  • The question is a bit subjective for my tastes, but are you already familiar with [the detection idiom](http://en.cppreference.com/w/cpp/experimental/is_detected)? And/or Boost.Hana's [`is_valid`](http://www.boost.org/doc/libs/1_65_1/libs/hana/doc/html/structboost_1_1hana_1_1type.html#a2d2e7e08e284f7e0bd1bd9c3ad0e0a2b)? – ildjarn Oct 15 '17 at 14:55
  • @ildjarn I only heard about hana, but don't know it – Artur Pyszczuk Oct 15 '17 at 15:58
  • "Better" in what respect? Are you asking if there is a better implementation of some `Is_string` trait? Or whether there is a better overall tactic than using some `Is_string` trait in the first place? – ildjarn Oct 15 '17 at 17:29
  • 1
    @ildjarn sorry for not to mention the idea. I used `c_str()` because `std::string` has it and `std::vector` has not. I think that even though in this example it is fine, `c_str()` should not be used to distinguish between `std::string` and `std::vector`. – Artur Pyszczuk Oct 15 '17 at 17:45

1 Answers1

6

I am not really sure if checking if c_str() exists is the better option I can get.

Ideally you'll be checking for what you actually want.

That can either be a set of known types or templates, or it can be a concept.

At the moment, you're checking for "the concept of having a c_str() member function which returns a pointer to constant chars".

The question is, what concept does your SFINAE'd function need?

If it will use the c_str() member, that's reasonable. But if it's going to use other members or types of the string, you probably want to build a compound concept to describe the parts of the interface you're going to exercise.

Of course, you may just want to confirm that it is actually a specialisation of std::string. It's difficult (impossible) to tell unless you state the use case.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • 1
    In fact `c_str()` was chosen because it is something that is a part of `std::string`, but not part of `std::vector`. I didn't mention that in the question and also that's why I asked if there is a better option. – Artur Pyszczuk Oct 15 '17 at 16:03
  • @ArturPyszczuk yes I see. string is almost 'vector-like' except that printing it like you would a vector, element by element makes no sense. When I have built overloaded emitter functions like this in the past I have delegated to partially specialised outputter functors rather than rely on overload selection. – Richard Hodges Oct 15 '17 at 17:10