SFINAE和参数数量

问题描述 投票:1回答:2

我有一个模板类C<T>,我打算用T实例化其他类ABC<T>有一个方法foo,其签名我想依赖于T是否被实例化为AB。例如,请考虑以下代码:

#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参数的类型。我想在C::call上制作T的签名(特别是参数数量)。因此,即使在ca.call(42)中有A::message(int)方法,我也会阻止A成为有效的电话。

有没有办法做到这一点?

c++ templates sfinae
2个回答
1
投票

我不知道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>>

0
投票

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.