有很多类似的问题,但我找不到这个问题:给定
template <typename T>
struct S {
int f(int x) const { return x; }
};
Run Code Online (Sandbox Code Playgroud)
我希望能够f
根据T
. 显而易见的事情不起作用:
#include <type_traits>
template <typename T>
struct MyProperty { static constexpr auto value = std::is_same_v<T, float>; };
template <typename T>
struct S {
template <typename = std::enable_if_t<MyProperty<T>::value>>
int f(int x) const { return x; }
};
int main() {
S<int> s;
}
Run Code Online (Sandbox Code Playgroud)
我能想到的最接近的是一个假人typename U = T
:
template <typename U = T, typename = std::enable_if_t<MyProperty<U>::value>>
int f(int x) const {
static_assert(std::is_same_v<T, U>, "Don't provide U.");
return x;
}
Run Code Online (Sandbox Code Playgroud)
它可以工作https://godbolt.org/z/8qGs6P8Wd但感觉很绕。有没有更好的办法?
如果您可以使用 C++20 或更高版本,请添加约束:
template<class T>
struct S {
int f(int x) const requires MyProperty<T>::value {
return x;
}
};
Run Code Online (Sandbox Code Playgroud)
在 C++17 中,您可以像现在一样执行此操作,或者将 移至enable_if
用于函数的返回类型。如果您将条件放在std::is_same_v<U, T>
tooenable_if
而不是 a 中static_assert
,那么如果您想启用其他f
s,它会对 SFINAE 更加友好。
template<class T>
struct S {
template<class U = T>
std::enable_if_t<std::is_same_v<U, T> && MyProperty<U>::value, int>
f(int x) const {
return x;
}
};
Run Code Online (Sandbox Code Playgroud)
如果您的类中有许多函数并且您只想在以下情况下启用,则另一个有用的选项MyProperty::value
是true
将所有这些函数放入基类中,并使用CRTP有条件地从该类继承。
struct empty {};
template<class T>
struct float_funcs {
T& Self() { return *static_cast<T*>(this); }
const T& Self() const { return *static_cast<const T*>(this); }
// put all functions depending on the MyProperty trait being true here:
int f(int x) const {
return x + Self().foo; // `foo` is accessible since we're a friend
}
};
template<class T> // added helper variable
inline constexpr bool MyProperty_v = MyProperty<T>::value;
// inherit from float_funcs<S<T>> if the condition is `true` or `empty` otherwise
template<class T>
struct S : std::conditional_t<MyProperty_v<T>, float_funcs<S<T>>, empty> {
private:
friend std::conditional_t<MyProperty_v<T>, float_funcs<S<T>>, empty>;
int foo = 1;
};
Run Code Online (Sandbox Code Playgroud)
有了这个,您就不需要 SFINAE 了f
,如果你尝试使用f
whenMyProperty<T>
不满足,你会得到一个明显的编译错误。f
在这种情况下甚至不以任何形式存在。