c++ - Using SFINAE to select the interface to implement -
i'm trying select interface concrete class implements based on template parameter. in simplified example below there 2 interfaces methods of different names - implementation
class needs provide method implementations, depending on template parameter.
if use inttype
- should implement intinterface
(getint()
, setint(int)
). if use doubletype
- should implement doubleinterface
(getdouble()
, setdouble(double)
).
in order achieve this, created traits class determines interface should used (interfacetype
), has parameter used sfinae.
the idea if use e.g. mytypetrait<type>::mytypeint
relevant trait class has no mytypeint
definition, compiler throw possible overload (for e.g. setint()
), , use one. that's dummys should kick in - have different arguments , they're not virtual.
however, doesn't work. see below compiler errors.
i'm using 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 case of inttype virtual typename mytypetrait<type>::mytypeint getint() const override { return 0; } virtual void setint(typename mytypetrait<type>::mytypeint value) override {} // dummys sfinae - used in case of doubletype typename int getint(int) const { return 0; } void setint() {} // actual interface implementation case of doubletype virtual typename mytypetrait<type>::mytypedouble getdouble() const override { return 0.0; } virtual void setdouble(typename mytypetrait<type>::mytypedouble value) override {} // dummys sfinae - used in 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; }
compiler errors:
1>c++-tests.cpp(50): error c2039: 'mytypedouble' : not member of 'mytypetrait<0>' 1> c++-tests.cpp(26) : see declaration of 'mytypetrait<0>' 1> c++-tests.cpp(61) : see reference 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++ not support default-int 1>c++-tests.cpp(50): warning c4183: 'getdouble': missing return type; assumed member function returning 'int' 1>c++-tests.cpp(51): error c2039: 'mytypedouble' : not 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 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 override specifier 'override' did not override base class methods 1>c++-tests.cpp(51): error c3668: 'implementation<0>::setdouble' : method override specifier 'override' did not override base class methods 1>c++-tests.cpp(42): error c2039: 'mytypeint' : not member of 'mytypetrait<1>' 1> c++-tests.cpp(33) : see declaration of 'mytypetrait<1>' 1> c++-tests.cpp(62) : see reference 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++ not support default-int 1>c++-tests.cpp(42): warning c4183: 'getint': missing return type; assumed member function returning 'int' 1>c++-tests.cpp(43): error c2039: 'mytypeint' : not 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 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 override specifier 'override' did not override base class methods 1>c++-tests.cpp(43): error c3668: 'implementation<1>::setint' : method override specifier 'override' did not override base class methods
i wasn't sure question whether wanted support either/or interface or complete/nop version of 2 interfaces.
here 1 solution former.
#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.setint(6); int = i.getint(); implementation<type::is_double> d {}; d.setdouble(6.0); int b = d.getdouble(); }
Comments
Post a Comment