3

In Herb Sutter's talk at C++Con 2014, among other things he discusses passing by value, by reference, and so forth. One technique he presents in this albeit contrived example is:

using namespace std;

class employee{
    string name_;
public:
    template<class String, class = enable_if_t<!is_same<decay_t<String>, string>::value>>

    void set_name(String&& name) noexcept(is_nothrow_assignable<string&, String>::value){
        name_ = forward<String>(name);
    }
};

I understand that String&&is a universal or forwarding reference as String is a deduced template type, and that one should therefore use forward<String>(name). Whilst I have some very limited experience with template metaprogramming, it is not obvious to me what is the purpose of the unamed tempate parameter, with the enable_if_t... and would appreciate an explanation to decipher its purpose. How does the noexcept work? What would have been wrong if one had naively written:

template<class String>
void set_name(String&& name){
    name_ = forward<String>(name);
}
curiousguy
  • 8,038
  • 2
  • 40
  • 58
user1997744
  • 411
  • 4
  • 16

2 Answers2

3

This is to ensure that set_name is only called with an l- or r-value reference to a std::string, allowing for any cv-qualifiers.

It works using SFINAE: if the result of decaying the String template argument is not the same type as std::string, enable_if_t will fail type checking, so that template will be removed from the candidate set.

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • One note, is if you watch the video, the "slide" version shows it as `!is_same`, where if you look at it over his shoulder as he's talking, it's just `is_same`. I suspect he wanted the `is_same` version. This is around 1:17:00 in the video. – Dave S Mar 31 '15 at 14:16
  • Yeah, that's what I assumed, otherwise the code seems rather strange. – TartanLlama Mar 31 '15 at 14:17
  • Just a note to explain the decay_t part: decay_t is the type you pass by value when you pass a String to a function. So the enable_if (when corrected to remove the "!") makes it so that set_name exists only when used with a type that will be std::string as it is passed into a function by value but acts as if there are no implicit conversions to std::string. This isn't the best example as I think most users would want to use set_name on any type that can be assigned to an instance of std::string - I don't mean to be critical of it but I hope that brings some perspective to the example. – codeshot Aug 23 '15 at 19:00
1

This unnamed template parameter is required because of std::enable_if_t usage. Parameter is not needed (used inside template function), so it can be unnamed.

std::enable_if_t works using SFINAE. If the parameter of std::enable_if_t is false, the code for function will not be generated for that parameter.

See some documentation for more information about std::enable_if_t. You can also look at Template Meta-Programming wikibook or SFINAE and enable_if article.

tmp
  • 1,079
  • 9
  • 16