Friend function with CRTP + enable_if is not working? - c++

The following code does not compile and I don't know why:
#include <type_traits>
// Base class definition
template<template<typename> class CRTP, typename T> class Base
{
// Friend function declaration
public:
template<template<typename> class CRTP0, typename T0, class>
friend int func(const Base<CRTP0, T0>& rhs);
// Protected test variable
protected:
int n;
};
// Friend function definition
template<template<typename> class CRTP0, typename T0,
class = typename std::enable_if<true>::type>
int func(const Base<CRTP0, T0>& rhs)
{
return rhs.n;
}
// Derived class definition
template<typename T> class Derived : public Base<Derived, T> {};
// Main
int main()
{
Derived<int> x;
func(x);
return 0;
}
GCC 4.6.2 (and GCC 4.7.1 on LWS) tells me that :
error: 'int Base<Derived, int>::n' is protected
Meaning that basically, the friendship is not correctly detected. As this is just an extract of my code, I would like to put the definition of the friend function outside of the class definition, like here. So, what is the problem and how to solve it ?
EDIT : I've modified the code to try to isolate the problem and make it far more readable. The current enable_if is always true but for my real code, I will have a "real" condition, here it is just to isolate the problem.
EDIT2 : The liveworkspace is here : friend function problem

I had similar problems with gcc. I think this is a compiler bug: Because your function template has three template parameters rather than the two in the friend declaration, it doesn't match them. In order for your intentions to work correctly with gcc, you must match the friend declaration exactly. This is most easily achieved by using the SFINAE on the function return type
// Friend function definition
template<template<typename> class CRTP0, typename T0>
typename std::enable_if<true,int>::type
func(const Base<CRTP0, T0>& rhs)
{
return rhs.n;
}

If you try to call func explicitly:
func<Derived, int, void>(x);
g++ complains with:
source.cpp:31:31: error: call of overloaded 'func(Derived<int>&)' is ambiguous
source.cpp:31:31: note: candidates are:
source.cpp:19:5: note: int func(const Base<CRTP0, T0>&) [with CRTP0 = Derived; T0 = int; <template-parameter-1-3> = void]
source.cpp:9:20: note: int func(const Base<CRTP0, T0>&) [with CRTP0 = Derived; T0 = int; <template-parameter-2-3> = void; CRTP = Derived; T = int]
I believe the problem is that the friend declaration is not being correctly identified with the function definition; instead another function template is being declared. This happens even if the class and function templates are predeclared.

Related

Timing of C++template specialization and constexpr function execution [duplicate]

Note: this seems to be a repost of a problem: C++ - Overload templated class method with a partial specilization of that method
I have boiled down a problem I am having with C++ template specialization down to a simple case.
It consists of a simple 2-parameter template class Thing, where I would like to specialize Thing<A,B>::doSomething() for B=int.
#include <cstdio>
// A 3-parameter template class.
template <class A, class B>
class Thing
{
public:
Thing(A a, B b) : a_(a), b_(b) {}
B doSomething();
private:
A a_;
B b_;
};
// The generic case works as expected.
template <class A, class B>
B Thing<A,B>::doSomething()
{
return b_;
}
// This specialization does not work!
template <class A>
int Thing<A,int>::doSomething()
{
return b_+1;
}
int main() {
// Setup our thing.
Thing<double,int> thing(1.0,2);
// This doesn't compile - but works with the generic case.
printf("Expecting 3, and getting %i\n", thing.doSomething());
// Clean up.
return 0;
}
Unfortunately, g++ exits with the error:
partial_specialization.cpp:30: error: invalid use of incomplete type ‘class Thing<A, int>’
partial_specialization.cpp:8: error: declaration of ‘class Thing<A, int>’
The clang++ compiler is a bit more verbose, but has the same problem:
partial_specialization.cpp:30:19: error: nested name specifier 'Thing<A, int>::' for declaration does not
refer into a class, class template or class template partial specialization
int Thing<A,int>::doSomething()
~~~~~~~~~~~~~~^
partial_specialization.cpp:32:12: error: use of undeclared identifier 'b_'
return b_+1;
^
2 errors generated.
I have read and understood that partial template specializations on functions aren't allowed - but I thought I was partially specializing over classes of Thing in this case.
Any ideas?
What I did: A workaround, as determined from the link provided by the accepted answer:
template< class T >
inline T foo( T const & v ) { return v; }
template<>
inline int foo( int const & v ) { return v+1; }
// The generic case works as expected.
template <class A, class B>
B Thing<A,B>::doSomething()
{
return foo(b_);
}
Partial specialization of a function template, whether it is member function template or stand-alone function template, is not allowed by the Standard:
template<typename T, typename U> void f() {} //okay - primary template
template<typename T> void f<T,int>() {} //error - partial specialization
template<> void f<unsigned char,int>() {} //okay - full specialization
But you can partially specialize the class template itself. You can do something like this:
template <class A>
class Thing<A,int> //partial specialization of the class template
{
//..
int doSomething();
};
template <class A>
int Thing<A,int>::doSomething() { /* do whatever you want to do here */ }
Note that when you partially specialize a class template, then the template parameter-list of member function (in its definition outside the class), must match the template parameter list of the class template partial specialization. That means, for the above partial specialization of the class template, you cannot define this:
template <class A>
int Thing<A,double>::doSomething(); //error
Its not allowed, because the template parameter-list in function definition didn't match the template parameter-list of the class template partial specialization. §14.5.4.3/1 from the Standard (2003) says,
The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.[...]
For more on this, read my answer here:
C++ - Overload templated class method with a partial specilization of that method
So what is the solution? Would you partially specialize your class along with all the repetitive work?
A simple solution would be work delegation, instead of partially specializing the class template. Write a stand-alone function template and specialize this as:
template <class B>
B doTheActualSomething(B & b) { return b; }
template <>
int doTheActualSomething<int>(int & b) { return b + 1; }
And then call this function template from doSomething() member function as:
template <class A, class B>
B Thing<A,B>::doSomething() { return doTheActualSomething<B>(b_); }
Since in your particular case, doTheActualSomething needs to know the value of only one member, namely b_, the above solution is fine, as you can pass the value to the function as argument whose type is the template type argument B, and specialization for int is possible being it full-specialization.
But imagine if it needs to access multiple members, type of each depends on the template type argument-list, then defining a stand-alone function template wouldn't solve the problem, because now there will be more than one type argument to the function template, and you cannot partially specialize the function for just, say, one type (as its not allowed).
So in this case you can define a class template instead, which defines a static non-template member function doTheActualSomething. Here is how:
template<typename A, typename B>
struct Worker
{
B doTheActualSomething(Thing<A,B> *thing)
{
return thing->b_;
}
};
//partial specialization of the class template itself, for B = int
template<typename A>
struct Worker<A,int>
{
int doTheActualSomething(Thing<A,int> *thing)
{
return thing->b_ + 1;
}
};
Notice that you can use thing pointer to access any member of the class. Of course, if it needs to access private members, then you've to make struct Worker a friend of Thing class template, as:
//forward class template declaration
template<typename T, typename U> struct Worker
template <class A, class B>
class Thing
{
template<typename T, typename U> friend struct Worker; //make it friend
//...
};
Now delegate the work to the friend as:
template <class A, class B>
B Thing<A,B>::doSomething()
{
return Worker<A,B>::doTheActualSomething(this); //delegate work
}
Two points to be noted here:
In this solution, doTheActualSomething is not a member function template. Its not enclosing class which is template. Hence we can partially specialize the class template anytime, to get the desired effect of the partial member function template specialization.
Since we pass this pointer as argument to the function, we can access any member of the class Thing<A,B>, even private members, as Worker<T,U> is also a friend.
Complete online demo : http://www.ideone.com/uEQ4S
Now there is still a chance of improvement. Now all instantiations of Worker class template are friends of all instantiation of Thing class template. So we can restrict this many-to-many friendship as:
template <class A, class B>
class Thing
{
friend struct Worker<A,B>; //make it friend
//...
};
Now only one instantiation of Worker class template is a friend of one instantiation of Thing class template. That is one-to-one friendship. That is, Worker<A,B> is a friend of Thing<A,B>. Worker<A,B> is NOT a friend of Thing<A,C>.
This change requires us to write the code in somewhat different order. See the complete demo, with all the ordering of class and function definitions and all:
http://www.ideone.com/6a1Ih
This is a very often found problem, and there is a surprisingly simple solution. I will show it in an artificial example, because it's more clearer than to use your code, and you will have to understand it to adapt it to your code
template<typename A, typename B>
struct TwoTypes { };
template<typename A, typename B>
struct X {
/* forwards ... */
void f() { fImpl(TwoTypes<A, B>()); }
/* special overload for <A, int> */
template<typename A1>
void fImpl(TwoTypes<A1, int>) {
/* ... */
}
/* generic */
template<typename A1, typename B1>
void fImpl(TwoTypes<A1, B1>) {
/* ... */
}
};
Explicitly specializing functions is never (almost never?) the right way. In my work as a programmer, I've never explicitly specialized a function template. Overloading and partial ordering is superior.

Template Default Arg Substitution failure in clang 3.3

This is regarding a test case which involves default argument
deduction/substitution. The test case can be summarized as :
template <class T, class = typename T::I>h(T){}
template <class T, class = typename T::I>j(T){}
class A
{
typedef int I;
friend void h<A>(A);
};
int main()
{
A a;
h(a);
j(a);
}
gcc-4.8.1 throws error for function j, since it has been not been declared friend nor it is private to class A and hence violates access rule for private member I(which is valid). gcc does not throw error for function h since it has been declared as friend to class A and hence can access private member I.
Clang throws error for both the functions. Error for function j (not declared friend is valid and as expected), but it throws error even for friend function h (error : deduction of default arg failed since I is a private member of class A). This violates the accessibility of the friend function.
I checked the code path. While clang is able to deduce the default argument, it checks for access rules before doing any substitution, and gives error. Can someone please provide guidance as to how should this be fixed?
You forgot the return type for the template functions.
This should solve the problem :
template <class T, class = typename T::I> void h(T){}
template <class T, class = typename T::I> void j(T){}
After fixing above errors, I still got errors, because
you declared the typedef in the private section. You need to make it public
you declared function friend wrongly. It has two template arguments (A::I will not work, since A is not complete type)
Fully compilable problem is here :
#include <iostream>
// Type your code here, or load an example.
template <class T, class = typename T::I> void h(T t){std::cout<<t.a<<std::endl;}
template <class T, class = typename T::I> void j(T t){std::cout<<t.a<<std::endl;}
class A
{
friend void h<A,int>(A);
friend void j<A,int>(A);
public :
typedef int I;
private :
int a;
};
int main()
{
A a;
h(a);
j(a);
}

enable_if : case of templated method of a template base inherited several times

If I have a template base class with a template method :
template <typename T>
class S
{
public:
template <typename U>
void f(U p, typename enable_if<is_same<T, U> >::type*dummy = 0)
{
std::cout << p << std::endl;
}
};
For the example, I simplify the method : it must "exists" only if T == U
If A is this class:
class A : public S<int> {};
Then I have what I want:
int i = 1;
A a;
a.f(i);
compiles, but
double d = 2.0;
a.f(d);
doesn't compile : error: no matching function for call to ‘A::f(double&)’
It is the expected behavior.
Now let's A inherit from S<double> also :
class A : public S<int>, public S<double> {};
Then the following code doesn't compile:
int i = 1;
A a;
a.f(i);
error: request for member ‘f’ is ambiguous
error: candidates are: template<class U> void S::f(U, typename
boost::enable_if<boost::is_same<T, U>, void>::type*) [with U = U, T =
double]
error: template<class U> void S::f(U, typename
boost::enable_if<boost::is_same<T, U>, void>::type*) [with U = U, T =
int]
I expected there is no ambiguity : f<int> exists only for S<int>
In the compiler error, we can notice that T is known when this piece of code is compiled, but not U (U = U).
Any explanation or "workaround" ?
Try this:
a.S<int>::f(i);
...or alternatively inject the function into A, e.g.
class A : public S<int>, public S<double>
{
public:
using S<int>::f;
using S<double>::f;
};
You are right it only exists in S, but two times. Once for each type, int and double. So in your case you will need to specify exactly which function you want to call. The solution from Nim works just like that.
Others have given good workarounds, but I want to answer that other question you had
I expected there is no ambiguity : f<int> exists only for S<int>.
You said a.f(i) so it first needs to look for name f in A. It finds two fs. In S<int> and S<double>. At name lookup time, it does not know yet that it later could have only selected S<int>::f as a winner because S<double>::f would be thrown away by SFINAE. The clear separation of name lookup and overload resolution and template argument deduction does not allow such intermingling.

make another instatiation's friend of a template class

template <typename T> class Foo;
template <typename T> int g(Foo<T> const&);
template <typename T> class Foo
{
public:
template <typename U> int f(Foo<U> const& p) const { return p.m; }
// which friend declaration will allow the above function to compile? The
// next one doesn't work.
template <typename U> friend void Foo<U>::template f<T>(Foo<T> const&) const;
// while this one work for g().
friend int g<T>(Foo<T> const&);
private:
int m;
};
template <typename T> int g(Foo<T> const& p) { return p.m; }
// Let's call them
void bar()
{
Foo<int> fi;
Foo<double> fd;
fd.f(fi);
g(fi);
}
The above doesn't compile with g++ nor Como. g() is here to show what I would like to do with f().
For instance, here are g++ messages:
foo.cpp:11: error: invalid use of template-id ‘f<T>’ in declaration of primary template
foo.cpp: In member function ‘int Foo<T>::f(const Foo<U>&) const [with U = int, T = double]’:
foo.cpp:27: instantiated from here
foo.cpp:17: error: ‘int Foo<int>::m’ is private
foo.cpp:7: error: within this context
and como's one:
"ComeauTest.c", line 11: error: an explicit template argument list is not allowed on
this declaration
template <typename U> friend void Foo<U>::template f<T>(Foo<T> const&) const;
^
"ComeauTest.c", line 7: error: member "Foo<T>::m [with T=int]" (declared at line 17)
is inaccessible
template <typename U> int f(Foo<U> const& p) const { return p.m; }
^
detected during instantiation of "int Foo<T>::f(const Foo<U> &)
const [with T=double, U=int]" at line 27
2 errors detected in the compilation of "ComeauTest.c".
Variants suggested by the error messages didn't either.
BTW, I know of the obvious work around
template <typename U> friend class Foo<U>;
Edit:
14.5.4/5 (of n3225, 14.5.3/6 of C++98 is similar but the following text is clearer in n3225) starts by
A member of a class template may be declared friend of a non-template class...
which could imply that a member of a class template may not be declared friend of a template class but my first interpretation would that this sentence was an introduction for the following explanations (mainly they apply to any specialisation, explicit or not, given that the prototype is correct).
I think you have to say template <> before the friend declaration so it knows you're friending a specialization.
EDIT: I can't get any error with your code, even making an instantiation and calling g. Can you post a minimal set of actual code that's causing the error, along with the error message?
Though I'm not 100% sure this is strictly standard conforming,
the following code can be compiled by ideone(gcc-4.3.4) and Comeau online:
template< class >
class Foo {
int m;
public:
template< class U > int f( Foo<U> const& p ) const { return p.m; }
template< class U > template< class V >
friend int Foo<U>::f( Foo<V> const& ) const;
};
void bar() {
Foo<int> fi;
Foo<double> fd;
fd.f( fi );
}
Hope this helps.

C++ template-function -> passing a template-class as template-argument

i try to make intensive use of templates to wrap a factory class:
The wrapping class (i.e. classA) gets the wrapped class (i.e. classB) via an template-argument to provide 'pluggability'.
Additionally i have to provide an inner-class (innerA) that inherits from the wrapped inner-class (innerB).
The problem is the following error-message of the g++ "gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)":
sebastian#tecuhtli:~/Development/cppExercises/functionTemplate$ g++ -o test test.cpp
test.cpp: In static member function ‘static classA<A>::innerA<iB>* classA<A>::createInnerAs(iB&) [with iB = int, A = classB]’:
test.cpp:39: instantiated from here
test.cpp:32: error: dependent-name ‘classA::innerA<>’ is parsed as a non-type, but instantiation yields a type
test.cpp:32: note: say ‘typename classA::innerA<>’ if a type is meant
As you can see in the definition of method createInnerBs, i intend to pass a non-type argument. So the use of typename is wrong!
The code of test.cpp is below:
class classB{
public:
template < class iB>
class innerB{
iB& ib;
innerB(iB& b)
:ib(b){}
};
template<template <class> class classShell, class iB>
static classShell<iB>* createInnerBs(iB& b){
// this function creates instances of innerB and its subclasses,
// because B holds a certain allocator
return new classShell<iB>(b);
}
};
template<class A>
class classA{
// intention of this class is meant to be a pluggable interface
// using templates for compile-time checking
public:
template <class iB>
class innerA: A::template innerB<iB>{
innerA(iB& b)
:A::template innerB<iB>(b){}
};
template<class iB>
static inline innerA<iB>* createInnerAs(iB& b){
return A::createInnerBs<classA<A>::template innerA<> >(b); // line 32: error occurs here
}
};
typedef classA<classB> usable;
int main (int argc, char* argv[]){
int a = 5;
usable::innerA<int>* myVar = usable::createInnerAs(a);
return 0;
}
Please help me, i have been faced to this problem for several days.
Is it just impossible, what i'm trying to do? Or did i forgot something?
Thanks, Sema
Line 32 should read:
return A::template createInnerBs<innerA>(b);
since createInnerBs is dependent on the template parameter A.
You'll also need to make the constructors of innerA and innerB public.
Here is the corrected code which compiles for me:
class classB{
public:
template < class iB>
class innerB{
iB& ib;
public:
innerB(iB& b)
:ib(b){}
};
template<template <class> class classShell, class iB>
static classShell<iB>* createInnerBs(iB& b){
// this function creates instances of innerB and its subclasses,
// because B holds a certain allocator
return new classShell<iB>(b);
}
};
template<class A>
class classA{
// intention of this class is meant to be a pluggable interface
// using templates for compile-time checking
public:
template <class iB>
class innerA: public A::template innerB<iB>{
public:
innerA(iB& b)
: A::template innerB<iB>(b){}
};
template<class iB>
static inline innerA<iB>* createInnerAs(iB& b);
};
template<class A>
template<class iB>
inline classA<A>::innerA<iB>* classA<A>::createInnerAs(iB& b)
{
return A::template createInnerBs<classA::template innerA>(b);
}
typedef classA<classB> usable;
int main (int argc, char* argv[]){
int a = 5;
usable::innerA<int>* myVar = usable::createInnerAs(a);
return 0;
}
Even if I think you're overcomplicating things... But I don't fully understand your use case.