admin管理员组

文章数量:1205176

I'm trying to write a function template, make, that constructs different objects based on the specified template parameter. Calling this function might look something like make<std::set<int>>(1, 8);. To do this, I am using SFINAE, but it's not clear to me whether it's better to use enable_if_t to specify the return type, or use it in the template specification.

As I see it, there are two possible options as outlined below:

#include <type_traits>
#include <set>
#include <vector>

/////////////////////////////////////////////////
// Option 1: Specify the return type
/////////////////////////////////////////////////

// make_1 for sets
template<typename return_type>
std::enable_if_t<std::is_same_v<return_type, std::set<int>>, return_type> make_1(int first, int second){
    return return_type({first, second});
}

// make_1 for vectors
template<typename return_type>
std::enable_if_t<std::is_same_v<return_type, std::vector<int>>, return_type> make_1(int first, int second){
    return return_type({second, first});
}

// make_1 for other different types
// ...

/////////////////////////////////////////////////
// Option 2: Use a template parameter
/////////////////////////////////////////////////

// make_2 for sets
template<typename return_type, std::enable_if_t<std::is_same_v<return_type, std::set<int>>, bool> = true>
return_type make_2(int first, int second){
    return return_type({first, second});
}

// make_2 for vectors
template<typename return_type, std::enable_if_t<std::is_same_v<return_type, std::vector<int>>, bool> = true>
return_type make_2(int first, int second){
    return return_type({second, first});
}

// make_2 for other different types
// ...

int main() {
    auto s1 = make_1<std::set<int>>(4, 5);
    auto v1 = make_1<std::vector<int>>(6, 7);

    auto s2 = make_2<std::set<int>>(7, 8);
    auto v2 = make_2<std::vector<int>>(9, 10);
}

For each of these options, there might be tens of different implementations to make objects of different types, not just the two (sets and vectors) specified above.

My questions

Is one of these options better or more performant than the other?

There are other questions (such as this one) that discuss why you might prefer to use a template parameter for stylistic reasons, and explain why one method might be easier to implement than the other, but but it doesn’t address any differences about how the functions are handled at compile time. It seems to me like they will both resolve to the same thing after substitution. Is this actually the case? If not, in what way does the compiler handle them differently?

Notes

I'm using C++17 and this can't be changed, but answers related to other standards are still very much welcome! Also, the types used in my actual project are custom types, rather than standard containers, so this question isn't really asking about different ways to construct containers.

Edit

I originally also said:

I know I need to be careful having function templates that only differ on the default values of the template parameters; does that mater here since the default value in option 2 depends on a template parameter with no default value?

The answer to this is yes, as pointed out by @NatanOliver in the comments. The edit I made to my mwe means I am no longer using default values for template parameters, rendering this question redundant.

本文标签: