简体   繁体   中英

Restricting function template parameter to certain types

I have a function with two template parameters

template<class X, class Y>
bool fun(X x, Y y) { ... }

I need to restrict second parameter to the following two cases: int y or vector<int> const& y . If I try to static_assert :

static_assert( std::is_same<int, Y>::value ||
               std::is_same<std::vector<int> const&, Y>::value,
               "unsupported Y class" );

Then the following does not compile

X x;
std::vector<int> y;
fun(x, y);

because Y is deduced to be vector<int> instead of vector<int> const& .

Is there a way to restrict Y the way I want?

PS: Of course, I can call fun<X, vector<int> const&>( x, y ) but I want automatic type deduction to work. Or I can copy and paste and have two functions respectively, but it is a long function with same body, which I keep changing, so I don't like synchronizing two copies.

Y will never be deduced as const vector<int>& . That will only happen if that type is explicitly provided by the user.

X x;
std::vector<int> y;
fun(x, y); // Y deduced as std::vector<int>
fun<X, const std::vector<int>&>(x, y); // Y deduced as const std::vector<int>&

So if you don't expect types to be used explicitly, you can just static_assert against the expected types:

static_assert( std::is_same<int, Y>::value ||
               std::is_same<std::vector<int>, Y>::value,
               "unsupported Y class" );

However, if you want to handle even the case where the caller provides the types explicitly, then you want to use std::decay :

using dY = typename std::decay<Y>::type;

That will drop the const and & qualifiers. And then, you can do your static assert with neither:

static_assert( std::is_same<int, dY>::value ||
               std::is_same<std::vector<int>, dY>::value,
               "unsupported Y class" );

It sounds like you want to be able to pass in anything that's implicitly convertible to int or const std::vector<int>& , but you want the actual parameter type to be int or const std::vector<int>& , and you don't want to repeat the implementation. So, do this:

template <class X, class Y>
bool actual_fun(X x, Y y) {
    // actual implementation
}

template <class X>
bool fun(X x, int y) {
    return actual_fun<X, int>(x, y);
}

template <class X>
bool fun(X x, const std::vector<int>& y) {
    return actual_fun<X, const std::vector<int>&>(x, y);
}

(You may want to wrap actual_fun in a namespace detail or something of that sort.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM