C++ SFINAE with CRTP, G++ compile error - c++

I would like to know if the following code are valid.
The original intension is that, I like a base class that dispatch calls to a certain member to either derived class members if it is there or fall back to default behaviors if derived class does not have this member. Another use is that this base class can be used by itself and the Derived template parameter becomes a implementation policy. Anyway, the following MWE compiles and runs correctly with clang++, Intel, icpc and MSVS. However it fails with g++ (from 4.4 to 4.6, any version I had a hand on) with the error message at the end of the question.
If I change the call at point (1), (2), (3) to call_dispatch (which was the sort of thing I did originally), g++ does not complain anymore. I don't think it is a good practice to have the dispatch function and the caller having the same name. I was just curious if it will work, and curiously enough to try it out (I have no idea how does this idea come to me). My rationale behind this is that, at pint (1), call is invoked with one parameter, so the overload resolution will not match its caller, the zero parameter one. It will not match the SFINAE one at point (2) either, since D2 does not have the member, and then it shall match the one at point (3). Just as in the situation when (1)-(3) are named call_dispatch.
But g++ does not agree with me and other compilers. So, is it an incorrect implementation of g++ or the code itself is invalid? Besides the error message is really confusing. Where does the void (B<D2>::*)() and &B<D2>::call come from? Int he called the member pointer was defined as D2's member.
#include <iostream>
#include <functional>
template <typename Derived>
class B
{
public :
void call ()
{
call<Derived>(0); //----------------------------------------- (1)
}
private :
template <typename D, void (D::*)()> class SFINAE {};
template <typename D>
void call (SFINAE<D, &D::call> *) //---------------------------- (2)
{
static_cast<Derived *>(this)->call();
}
template <typename D>
void call (...) //--------------------------------------------- (3)
{
std::cout << "Call B" << std::endl;
}
};
class D1 : public B<D1>
{
public :
void call ()
{
std::cout << "Call D1" << std::endl;
}
};
class D2 : public B<D2> {};
int main ()
{
D1 d1;
D2 d2;
d1.call();
d2.call();
return 0;
}
Error:
foo.cpp: In member function ‘void B<Derived>::call() [with Derived = D2]’:
foo.cpp:48:13: instantiated from here
foo.cpp:11:9: error: ‘&B<D2>::call’ is not a valid template argument for type ‘void (D2::*)()’ because it is of type ‘void (B<D2>::*)()’
foo.cpp:11:9: note: standard conversions are not allowed in this context
Edit
Though I have not fully understand what goes wrong in the above code yet. But I think there is a another way without specifically construct a SFINAE class but archive the same effect.
#include <iostream>
template <typename Derived>
class B
{
public :
void call ()
{
call_dispatch(&Derived::call);
}
template <typename C>
void call_dispatch (void (C::*) ())
{
static_cast<Derived *>(this)->call();
}
void call_dispatch (void (B<Derived>::*) ())
{
std::cout << "Call B" << std::endl;
}
private :
};
class D1 : public B<D1>
{
public :
void call ()
{
std::cout << "Call D1" << std::endl;
}
};
class D2 : public B<D2> {};
int main ()
{
D1 d1;
D2 d2;
d1.call();
d2.call();
return 0;
}
Basically, because D1 and D2 both are derived from B, so the expression &Derived::call will always be resolved. In D1 it resolved to &D1::call, then the template version member is used. In D2, it does not have its own call, so &D2::call is resolved to &B::call, and thanks to
#DavidRodríguez-dribeas, who points out that now &D2::call has the type B::call, therefore the template and the non-template members equally match, but non-template is preferred. So the default call is used.
Can help me see if there is any defect in this new code?

Where does the void (B::*)() and &B::call come from?
The type of a pointer to member is not the type on which you obtained such pointer, but the type on which the member is defined.
struct base { int x; };
struct derived : base {};
int main() {
std::cout << std::is_same< decltype(&derived::x), int (base::*) >::value << std::endl;
}
The above program prints 1. In your case, when you use &D::base, the compiler finds B<D2>::call as a member of the base template, and that is the result of the expression: void (B<D2>::*)().

Your instantiation of SFINAE is expecting the function pointer template argument to be of type void (D2::*)(), but instead is of type void (B<D2>::*)() (because call is not overidden in D2, it uses the one defined in B<D2>).
Edit
It is not the instantiation of template <typename D>
void call (SFINAE<D, &D::call> *) that is failing here. There is no substitution error there. The substitution error occurs with the instantiation of SFINAE<B<D2>, &B<D2>::call>, of which there is no fallback instantiation, hence the error.

Related

Overloading a C++ template class virtual function

Below is the code to recreate the problem I am having. Base class is a template class with the virtual function foo. foo has a default implementation that adds the passed in arguments.
SimpleDerived derives from Base, specializing it with std::string. SimpleDerived overloads the virtual Base<T>::foo() function. This class compiles fine and its foo outputs as expected when called in main.
#include <iostream>
template<class T>
struct Base
{
virtual void foo(T val)
{
T local = val + val; // THE OFFENDING LINE OF CODE
std::cout << "Base" << std::endl;
}
};
struct SimpleDerived : public Base<std::string>
{
virtual void foo(std::string val)
{
std::cout << "SimpleDerived" << std::endl;
}
};
struct SimpleObject
{
int value;
};
struct ComplexDerived : public Base<SimpleObject>
{
virtual void foo(SimpleObject val)
{
std::cout << "ComplexDerived" << std::endl;
}
};
int main(void)
{
Base<int> base;
base.foo(2);
SimpleDerived simpleDerived;
simpleDerived.foo("hello world");
SimpleObject object;
ComplexDerived complexDerived;
complexDerived.foo(object);
return 0;
}
ComplexDerived derives from Base, specializing it with a custom struct SimpleObject. ComplexDerived overloads foo as well. However, this is the root of the problem. If I try to compile this I get:
quicktest.cpp: In member function ‘void Base<T>::foo(T) [with T = SimpleObject]’:
quicktest.cpp:47:1: instantiated from here
quicktest.cpp:8:19: error: no match for ‘operator+’ in ‘val + val’
Obviously, there is no operator "+" for SimpleObject. But here is my confusion.. the compiler is being asked to implement Base<SimpleObject>::foo because this is what ComplexDerived inherits from. However, I never use or call Base<SimpleObject>::foo. So should the compiler be trying to generate this base class function?
Paragraph 14.7.1/10 of the C++11 Standard specifies:
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual
member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates
a virtual member function of a class template if the virtual member function would not otherwise be instantiated. [...]
In other words, the behavior in this case is implementation-specific.
While in theory the compiler could figure out that the call to the base class's implementation of foo() won't ever be invoked (since the function call does not occur through a reference or pointer) and avoid instantiating it, this behavior is not mandated by the Standard.

Force deriving from a class virtually

We have a special framework for interfaces in our project, and part of the requirements is that classes which represent an interface may only be used as virtual base classes, not as non-virtual ones. Is there a way to enforce this in code? That is, produce a compilation error if the class is derived from non-virtually.
I have access to C++11 as implemented by VS 2010: this means static_assert, enable_if and <type_traits> are available.
IMO, there is no clean and platform independent solution available to this problem.
The best way is to manually go and change each and every inheritance to virtual inheritance.
To accomplish that, identifying the derived classes of your interface (say class Base) is easy(!). Below steps can be followed for that:
Make class Base as final (c++11); i.e. class Base final { ...
Compile the code, it will generate compiler error for all its
derived classes
Go and check every derived class and make the inheritance as
virtual
Remove the final keyword and compile the code successfully
This process (unfortunately) has to be followed periodically, whenever you want to do such sanity checking.
This is possible to check at compile time. The key is that, if we have a diamond pattern:
You can unambiguously cast D& to A&. However, if the inheritance is non-virtual:
the cast would ambiguous. So let's try to make a diamond!
template <typename Base, typename Derived>
class make_diamond {
struct D2 : virtual Base { }; // this one MUST be virtual
// otherwise we'd NEVER have a diamond
public:
struct type : Derived, D2 { };
};
At which point it's just another void_t-style type trait:
template <typename Base, typename Derived, typename = void>
struct is_virtual_base_of : std::false_type { };
template <typename Base, typename Derived>
struct is_virtual_base_of<Base, Derived, void_t<
decltype(static_cast<Base&>(
std::declval<typename make_diamond<Base, Derived>::type&>()))
>> : std::true_type { };
If the cast is unambiguous, the expression in the partial specialization will be valid, and that specialization will be preferred. If the cast is ambiguous, we'll have a substitution failure, and end up with the primary. Note that Base here doesn't actually need to have any virtual member functions:
struct A { };
struct B : public A { };
struct C : virtual A { };
std::cout << is_virtual_base_of<A, B>::value << std::endl; // 0
std::cout << is_virtual_base_of<A, C>::value << std::endl; // 1
And if it has any pure virtual member functions, we don't have to override them since we're never actually constructing an object.
struct A2 { virtual void foo() = 0; };
struct B2 : public A2 { void foo() override { } };
struct C2 : virtual A2 { void foo() override { } };
std::cout << is_virtual_base_of<A2, B2>::value << std::endl; // 0
std::cout << is_virtual_base_of<A2, C2>::value << std::endl; // 1
Of course if your class is marked final, this won't work at all. But then, if it were final, it wouldn't matter what kind of inheritance it had anyway.
Interesting problem. You may be able to get close to what you want by hiding the interface class and exposing a concrete class that inherits from the interface virtually. This obviously entails some workarounds and awkwardness, but it might be adaptable to your needs. Here's an example:
#include <iostream>
using namespace std;
class Hide {
struct VInterface {
void foo() const { cout << "VInterface::foo()\n"; }
VInterface const &as_interface() const { return *this; }
protected:
virtual ~VInterface() { }
};
public:
struct VBase : virtual VInterface {
};
};
typedef Hide::VBase VBase;
struct VDiamond1 : VBase { };
struct VDiamond2 : VBase { };
struct VConcrete : VDiamond1, VDiamond2 { };
int main() {
VConcrete vc;
auto const &vi = vc.as_interface();
vi.foo();
}
It may be possible to reconstruct a name using decltype() and as_interface() that may be usable for inheritance, but the ones I tried resulted in compiler errors that the destructor was protected, so I expect that if it is possible, it's at least relatively difficult and might be sufficient for your needs.

What is non overloaded pointer to member and overloaded pointer to member?

I am reading C++ programming language by Bjarne Stroustrup. I came across the statement in templates section.
A template argument can be a constant expression (§C.5), the address of an object or function
with external linkage (§9.2), or a non overloaded pointer to member (§15.5).
What is non overloaded pointer to member? Can someone give example?
A non-overloaded pointer-to-member is as the name states -- a pointer to a member that hasn't overloaded a superclass. Here's an example I've just put together of what will and won't work:
#include <iostream>
class Foo {
public:
virtual void printN() { std::cout << 42; }
};
class Bar : public Foo {
public:
void printN() { std::cout << 31; }
};
template <typename T, typename C>
class SomeTemplate {
public:
void PrintData(T d) { C c; (c.*d)(); }
};
int main() {
SomeTemplate<void (Foo::*) (), Foo> t; // Compiles - '42'
t.PrintData(&Foo::printN);
SomeTemplate<void (Bar::*) (), Bar> t; // Compiles - '31'
t.PrintData(&Bar::printN);
SomeTemplate<void (Foo::*) (), Bar> t; // Won't compile, can't convert overloaded pointers
t.PrintData(&Foo::printN);
return 0;
}
In PrintData, an instance of the class is created and the member pointer passed is dereferenced on the instantiated version of the class, resulting in it's underlying function being called.
Templates make this approach somewhat more flexible, but I've yet to find a reason to use code such as this in a real situation however -- if anyone can find a one I'd love to be enlightened..

C++ overloaded template functions in derived classes

I know you can overload templates based on their template parameters:
template <class T> void test() {
std::cout << "template<T>" << std::endl;
}
void test() {
std::cout << "not a template" << std::endl;
}
then inside some function:
test<int>();
test();
will correctly resolve which of the 2 different versions of test() you want. However, if I now do this inside classes with inheritance:
class A {
public:
void test() {
std::cout << "A::Test: not a template" << std::endl;
}
};
class B : public A {
public:
template <class T>
void test() {
std::cout << "B::Test: template<T>" << std::endl;
}
};
then inside a function:
B b;
b.test<int>();
b.test();
b.test<int>(); works but b.test(); does not:
error: no matching function for call to ‘B::test()’
note: candidate is:
note: template<class T> void B::test()
Why is this/ is there any way to make it correctly resolve the 2 versions based on the template arguments?
As always, a name defined in a derived class hides uses of the same name in a base class. To hoist the name in the base class into the derived class, add
using A::test;
to the derived class.
What you are observing is called name hiding. The name test in the derived class hides test in the base class. Without a using declaration that name will never be found when called through the exact type of that object (casting to base or explicitly qualifying the call also helps).

Doubt with the template instantiation problem in the below snippet of a user defined class [duplicate]

This question already has answers here:
"template polymorphism" when calling function for templated parameter of base type, with derived type?
(2 answers)
Closed 8 years ago.
Couldn't find anything relevant in forums So ,Please help me with this code .I'm brushing up my c++ concepts and met with a strange error
#include<iostream>
using namespace std ;
class base
{
int i ;
public:
virtual void f(){cout<<"base" ; return ;};
};
class derived: public base
{
int j ;
public:
void f() {cout<<"derived" ; return ;}
};
template<class T>
class test
{
public:
test(T b)
{
b.f(); cout<<endl<<" "<<sizeof(b)<<endl;
}
};
int main()
{
base b ;
derived d;
test<derived> t(b); // cannot instantiate user defined type without typename
}
The following code fails to compile with the following error :
test.cpp: In function ‘int main()’:
test.cpp:28: error: no matching function for call to ‘test<derived>::test(base&)’
test.cpp:19: note: candidates are: test<T>::test(T) [with T = derived]
test.cpp:17: note: test<derived>::test(const test<derived>&)
I can make wild guess and arrive at an answer at to why did this happen .If i instantiate a new base class from the template , everything works just fine , but not this one .
Can somebody tell me a good source for template instantiations and what are the rules/semantics , what is happening behind the curtain ?
thanks
Your test snippet effectively defines this:
test::test(derived&)
As the error says, you're trying to invoke this instead:
test::test(base&)
If i instantiate a new base class from the template , everything works just fine.
Similarly, I'm sure, if you passed "d" instead of "b", everything would also work fine.
You should be able to reproduce the same scenario without templates: just defined a member function that takes "derived" as an argument, and see what happens :)
base is not a complete derived type, so you'll have to provide a constructor inside your template that fills in the missing details.
template<class T> //original template
class test
{
public:
test(T b)
{
b.f();
cout<<endl<<" "<<sizeof(b)<<endl;
}
};
When you create an instance of this template based on derived, the compiler translates it to a class, which essentially boils down to this
class derivedtest
{
public:
derivedtest(derived b)
{
b.f();
cout<<endl<<" "<<sizeof(b)<<endl;
}
};
The default constructor is not generated any more. However, a default copy constructor is still created.
derivedtest::derivedtest(derived const&);
As you can see, there is no way to pass base (by reference or copy) into the class.
The solution is to provide a constructor inside your template that fills in the missing details:
template<class T>
class test
{
public:
test(base const& item)
: base(item)
{
}
test(T b)
{
b.f();
cout<<endl<<" "<<sizeof(b)<<endl;
}
};
By the way, your base should most likely have a virtual destructor
and test(T b) should be test(T const& b)