SFINAE 和参数数量

SFINAE and number of parameters

本文关键字:数数 参数 SFINAE      更新时间:2023-10-16

我有一个模板类C<T>我打算用T实例化它,就像其他一些类一样ABC<T>有一个方法foo我想根据T的实例化为A还是B。例如,请考虑以下代码:

#include <iostream>
#include <string>
class A {
public:
void message() {
std::cout << "message with no args" << std::endl;
}
};
class B {
public:
void message(int x) {
std::cout << "message with " << x << std::endl;
}
};
template<typename T>
class C {
private:
T internal;
public:
C(T& x) {
internal = x;
}
void call() {
internal.message();
}
void call(int x) {
internal.message(x);
}
};
int main(int argc, char* argv[]) {
A a;
B b;
C<A> ca(a);
C<B> cb(b);
ca.call();
cb.call(42);
//  ca.call(42);  ERROR HERE
return 0;
}

这将正确运行。ca.call(42)会引发编译错误,因为没有方法A::message(int)。但是,如果我出于某种原因引入了A::message(int)的方法A,代码可能允许调用ca.call(42),我想阻止。

我知道 SFINAE 技术将允许声明一个方法C::call(T::call_type x)其中T::call_type将是每个预期的T实例化的 typedef。但是,这只允许我更改C::call参数的类型。相反,我想在T上签名(特别是参数的数量)C::call.因此,即使AA::message(int)了方法,我也会阻止ca.call(42)成为有效的调用。

有什么办法可以做到这一点吗?

我不知道 SFINAE 的所有来龙去脉,但你怎么看这个?

template <
typename = std::enable_if_t<std::is_same<std::decay_t<T>, A>::value>>
void call() {
internal.message();
}
template <
typename = std::enable_if_t<std::is_same<std::decay_t<T>, B>::value>>
void call(int x) {
internal.message(x);
}

您也可以使用== false

template <
typename = std::enable_if_t<std::is_same<std::decay_t<T>, B>::value == false>>

您可以使用模板专用化来执行此操作:

// Main template used by every other type T.
template<typename T>
class C; // or some other implementation.
// This gets used for T = A.
template<>
class C<A> {
private:
A internal;
public:
C(A& x) {
internal = x;
}
void call() {
internal.message();
}
};
// This gets used for T = B.
template<>
class C<B> {
private:
B internal;
public:
C(B& x) {
internal = x;
}
void call(int x) {
internal.message(x);
}
};

如果你不喜欢这样,你需要复制一些通用代码,那么你可以有一个基类,其中包含所有这些常见的东西,并在每个专用化中继承它。