Cropping objects using std :: enable_if

I am trying to use std::enable_if to specialize a class if one of its subclasses has a specific member function. Otherwise, it should use the default implementation, which is defined in the base class.

 #include <boost/mpl/list.hpp> #include <boost/function_types/function_type.hpp> #include <boost/tti/has_member_function.hpp> #include <iostream> #include <type_traits> #include <memory> BOOST_TTI_HAS_MEMBER_FUNCTION(f2) class Base { public: virtual double f1(double x, double y) const { std::cout << "Called Base Method" << std::endl; return 0.0; } }; template<typename Derived> class A : public Base { public: template<typename T = Derived> typename std::enable_if < has_member_function_f2< T , double , boost::mpl::list<double> , boost::function_types::const_qualified >::value , double >::type f1(double x, double y) const { std::cout << "Called Derived Method" << std::endl; return static_cast<const Derived* const>(this)->f2(x); } }; class B : public A<B> { public: double f2(double x) const { return 1.0; } }; int main() { std::unique_ptr<Base> base_instance( new B ); std::cout << base_instance->f1(100.0, 10.0) << std::endl; B b_instance; std::cout << b_instance.f1(100.0, 10.0) << std::endl; return 0; } 

I expected it to print

 Called Derived Method 1 Called Derived Method 1 

however instead i get

 Called Base Method 0 Called Derived Method 1 

so it looks like an object is fragmenting. For life, I cannot understand why this would be so if someone could help me, which would be very grateful.

If this helps, it compiles with g ++ 4.7.2

+7
c ++ c ++ 11 virtual-functions enable-if object-slicing
source share
2 answers

@Sebastian's answer explains the problem, but the proposed solution will be problematic: you cannot specialize a base class template on the properties of a derived class using CRTP, since the derived class is not completed when the base class is created. I would suggest that instead you always override f1 in A and use tag dispatch to determine whether to send to f2 in a derived class or the default implementation in Base :

 template<typename Derived> class A : public Base { double f1_impl(boost::mpl::true_, double x, double) const { std::cout << "Called Derived Method\n"; return static_cast<const Derived*>(this)->f2(x); } double f1_impl(boost::mpl::false_, double x, double y) const { return Base::f1(x, y); } public: double f1(double x, double y) const override { using has_f2 = typename has_member_function_f2 < Derived , double , boost::mpl::list<double> , boost::function_types::const_qualified >::type; return f1_impl(has_f2{}, x, y); } }; 

Demo

+3
source share

Template functions cannot be virtual. It also means that the template function will never override the virtual function in the base class, even if the corresponding signature of the instantiation will match.

To achieve what you want, you need to specialize A as a whole to provide a member in one version and not in another.

+8
source share

All Articles