将函数模板参数限制为某些类型

Restricting function template parameter to certain types

我有一个带有两个模板参数的函数

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

我需要将第二个参数限制为以下两种情况:int yvector<int> const& y。如果我尝试 static_assert:

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

那么下面不编译

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

因为 Y 被推断为 vector<int> 而不是 vector<int> const&

有没有办法按照我想要的方式限制 Y?

PS:当然,我可以调用 fun<X, vector<int> const&>( x, y ),但我希望自动类型推导起作用。或者我可以复制和粘贴,分别有两个函数,但它是一个长函数,主体相同,我一直在改变,所以我不喜欢同步两个副本。

Y 永远不会被推断为 const vector<int>&。只有当用户明确提供该类型时才会发生这种情况。

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>&

因此,如果您不希望明确使用类型,您可以 static_assert 反对预期的类型:

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

但是,如果您甚至想处理调用者显式提供类型的情况,那么您想要使用 std::decay:

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

这将删除 const& 限定符。然后,你可以用两者都不做你的静态断言:

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

听起来您希望能够传递任何可隐式转换为 intconst std::vector<int>& 的内容,但您希望实际参数类型为 intconst std::vector<int>&,并且您不想重复执行。所以,这样做:

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

(您可能希望将 actual_fun 包装在 namespace detail 或类似的东西中。)