我试图根据模板参数选择具体类实现的接口(interface)。在下面的简化示例中,有两个具有不同名称的方法的接口(interface) - Implementation
类需要提供方法实现,具体取决于模板参数。
如果我使用IntType
- 它应该实现IntInterface
( getInt()
和 setInt(int)
)。
如果我使用 DoubleType
- 它应该实现DoubleInterface
( getDouble()
和 setDouble(double)
)。
为了实现这一目标,我创建了一个特征类,它确定应使用哪个接口(interface) ( InterfaceType
),但还有另一个用于 SFINAE 的参数。
这个想法是,如果我使用例如MyTypeTrait<Type>::MyTypeInt
但相关特质类没有MyTypeInt
定义时,编译器将抛出这种可能的重载(例如 setInt()
),并使用另一个重载。这就是假人应该发挥作用的地方 - 他们有不同的论点,而且他们不是虚拟的。
但是,它不起作用。请参阅下面的编译器错误。
我使用的是 Visual Studio 2013 (VC12)。
struct IntInterface
{
virtual int getInt() const = 0;
virtual void setInt(int value) = 0;
};
struct DoubleInterface
{
virtual double getDouble() const = 0;
virtual void setDouble(double value) = 0;
};
const int IntType = 0;
const int DoubleType = 1;
template <int Type>
struct MyTypeTrait;
template <>
struct MyTypeTrait<IntType>
{
using MyTypeInt = int;
using InterfaceType = IntInterface;
};
template <>
struct MyTypeTrait<DoubleType>
{
using MyTypeDouble = double;
using InterfaceType = DoubleInterface;
};
template <int Type>
struct Implementation : public MyTypeTrait<Type>::InterfaceType
{
// Actual interface implementation for the case of IntType
virtual typename MyTypeTrait<Type>::MyTypeInt getInt() const override { return 0; }
virtual void setInt(typename MyTypeTrait<Type>::MyTypeInt value) override {}
// Dummys for SFINAE - to be used in the case of DoubleType
typename int getInt(int) const { return 0; }
void setInt() {}
// Actual interface implementation for the case of DoubleType
virtual typename MyTypeTrait<Type>::MyTypeDouble getDouble() const override { return 0.0; }
virtual void setDouble(typename MyTypeTrait<Type>::MyTypeDouble value) override {}
// Dummys for SFINAE - to be used in the case of IntType
typename double getDouble(int) const { return 0.0; }
void setDouble() {}
};
int main(int argc, char* argv[])
{
Implementation<IntType> myInt;
Implementation<DoubleType> myDouble;
}
编译器错误:
1>c++-tests.cpp(50): error C2039: 'MyTypeDouble' : is not a member of 'MyTypeTrait<0>'
1> c++-tests.cpp(26) : see declaration of 'MyTypeTrait<0>'
1> c++-tests.cpp(61) : see reference to class template instantiation 'Implementation<0>' being compiled
1>c++-tests.cpp(50): error C2146: syntax error : missing ';' before identifier 'getDouble'
1>c++-tests.cpp(50): error C2433: 'Implementation<0>::MyTypeDouble' : 'virtual' not permitted on data declarations
1>c++-tests.cpp(50): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c++-tests.cpp(50): warning C4183: 'getDouble': missing return type; assumed to be a member function returning 'int'
1>c++-tests.cpp(51): error C2039: 'MyTypeDouble' : is not a member of 'MyTypeTrait<0>'
1> c++-tests.cpp(26) : see declaration of 'MyTypeTrait<0>'
1>c++-tests.cpp(51): error C2061: syntax error : identifier 'MyTypeDouble'
1>c++-tests.cpp(55): error C2535: 'void Implementation<0>::setDouble(void)' : member function already defined or declared
1> c++-tests.cpp(51) : see declaration of 'Implementation<0>::setDouble'
1>c++-tests.cpp(50): error C3668: 'Implementation<0>::getDouble' : method with override specifier 'override' did not override any base class methods
1>c++-tests.cpp(51): error C3668: 'Implementation<0>::setDouble' : method with override specifier 'override' did not override any base class methods
1>c++-tests.cpp(42): error C2039: 'MyTypeInt' : is not a member of 'MyTypeTrait<1>'
1> c++-tests.cpp(33) : see declaration of 'MyTypeTrait<1>'
1> c++-tests.cpp(62) : see reference to class template instantiation 'Implementation<1>' being compiled
1>c++-tests.cpp(42): error C2146: syntax error : missing ';' before identifier 'getInt'
1>c++-tests.cpp(42): error C2433: 'Implementation<1>::MyTypeInt' : 'virtual' not permitted on data declarations
1>c++-tests.cpp(42): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c++-tests.cpp(42): warning C4183: 'getInt': missing return type; assumed to be a member function returning 'int'
1>c++-tests.cpp(43): error C2039: 'MyTypeInt' : is not a member of 'MyTypeTrait<1>'
1> c++-tests.cpp(33) : see declaration of 'MyTypeTrait<1>'
1>c++-tests.cpp(43): error C2061: syntax error : identifier 'MyTypeInt'
1>c++-tests.cpp(47): error C2535: 'void Implementation<1>::setInt(void)' : member function already defined or declared
1> c++-tests.cpp(43) : see declaration of 'Implementation<1>::setInt'
1>c++-tests.cpp(42): error C3668: 'Implementation<1>::getInt' : method with override specifier 'override' did not override any base class methods
1>c++-tests.cpp(43): error C3668: 'Implementation<1>::setInt' : method with override specifier 'override' did not override any base class methods
最佳答案
从这个问题中我不能完全确定您是否想要支持任一/或接口(interface)或这 2 个接口(interface)的完整/NOP 版本。
这是针对前者的一种解决方案。
#include <utility>
#include <type_traits>
struct IntInterface
{
virtual int getInt() const = 0;
virtual void setInt(int value) = 0;
};
template<class TrueFalse>
struct IntInterfaceImpl {};
template<>
struct IntInterfaceImpl<std::true_type> : IntInterface
{
int getInt() const override { return i_; }
void setInt(int value) override { i_ = value; }
int i_;
};
struct DoubleInterface
{
virtual double getDouble() const = 0;
virtual void setDouble(double value) = 0;
};
template<class TrueFalse>
struct DoubleInterfaceImpl {};
template<>
struct DoubleInterfaceImpl<std::true_type> : DoubleInterface
{
double getDouble() const override { return i_; }
void setDouble(double value) override { i_ = value; }
double i_;
};
enum type {
is_int,
is_double
};
template<type T>
struct Implementation
: IntInterfaceImpl<std::integral_constant<bool, T == is_int>>
, DoubleInterfaceImpl<std::integral_constant<bool, T == is_double>>
{
};
int main()
{
Implementation<type::is_int> i {};
i.setInt(6);
int a = i.getInt();
Implementation<type::is_double> d {};
d.setDouble(6.0);
int b = d.getDouble();
}
关于c++ - 使用 SFINAE 选择要实现的接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39111474/