make another instatiation's friend of a template class - c++

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.

Related

c++ partial template specialization with requires statement: error: out-of-line definition of 'foo' from class Bar<T> without definition

Consider the following code which attempts to implement a partial specialization of class Bar. In the first case, the foo member function is defined inline and in the second case out of line. The out of line definition produces a compile error which I cannot figure out:
error: out-of-line definition of 'foo' from class 'Bar<T>' without definition
template<class T>
struct Bar;
template<class T>
requires std::is_same_v<T, int>
struct Bar<T> {
int foo(T a) {
return a + 5;
}
};
template<class T>
requires std::is_same_v<T, double>
struct Bar<T> {
double foo(T a);
};
template<class T>
requires std::is_same_v<T, double>
double Bar<T>::foo(T a) {
return a + 5;
};
I am using clang-11 with the c++20 compilation option. I am unsure if this is my misunderstanding, a feature or a bug. Any help is appreciated.
Might be clang bug. It was reported at https://bugs.llvm.org/show_bug.cgi?id=50276.
Anyway GCC is fine

Accessing Protected Attribute of Template Class

The following code doesn't work because the t member function can't access the attribute of its argument object.
How to declare template method t of template class A as a friend function of A?
For the code without template, there is no need to declare friend.
Code:
template <typename T>
class A{
protected:
T a;
public:
A(int i){
a = i;
}
template <typename T1>
void t(const A<T1> & Bb){
a = Bb.a;
}
};
int main(void){
A<int> Aa(5);
A<float> Bb(0);
Aa.t(Bb);
}
Compiler Error (icc test.cpp):
test.cpp(11): error #308: member "A<T>::a [with T=float]" (declared at line 4) is inaccessible
a = Bb.a;
^
detected during instantiation of "void A<T>::t(const A<T1> &) [with T=int, T1=float]" at line 17
Code without template:
class A{
protected:
int a;
public:
A(int i){
a = i;
}
void t(const A & Bb){
a = Bb.a;
}
};
int main(void){
A Aa(5);
A Bb(0);
Aa.t(Bb);
}
You can make all template instantiations friends of one another.
template <typename T>
class A {
protected:
// This makes A<int> friend of A<float> and A<float> friend of
// A<int>
template <typename T1> friend class A;
T a;
public:
A(int i){
a = i;
}
template <typename T1>
void t(const A<T1> & Bb){
a = Bb.a;
}
};
int main(void){
A<int> Aa(5);
A<float> Bb(0);
Aa.t(Bb);
}
A<T> and A<T1> are two different types, if T and T1 are two different types. You might as well replace A<T> with Foo and A<T1> with Bar in such a scenario. At that point it should be fairly obvious why you would need to make Foo and Bar friends (ehm, A<T> and A<T1> where T and T1 are not the same type).
Now, take a look at your error:
detected during instantiation of "void A<T>::t(const A<T1> &) [with T=int, T1=float]"
It's telling you it's calling your t() function on an object of type A<T>, passing in an object of type A<T1> as a parameter, where T=int and T1=float. This makes the object that's calling the function of a different class (A<int>) than the class of the object being used as the parameter (A<float>), and since they're different classes, they can't access each others' protected members without being friends.

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);
}

Friend function with CRTP + enable_if is not working?

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.

C++ template gotchas

just now I had to dig through the website to find out why template class template member function was giving syntax errors:
template<class C> class F00 {
template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here
I now realize that template brackets are treated as relational operators. To do what was intended the following bizarre syntax is needed, cf Templates: template function not playing well with class's template member function:
f.template bar<T>();
what other bizarre aspects and gotcha of C++/C++ templates you have encountered that were not something that you would consider to be common knowledge?
I got tripped up the first time I inherited a templated class from another templated class:
template<typename T>
class Base {
int a;
};
template<typename T>
class Derived : public Base<T> {
void func() {
a++; // error! 'a' has not been declared
}
};
The problem is that the compiler doesn't know if Base<T> is going to be the default template or a specialized one. A specialized version may not have int a as a member, so the compiler doesn't assume that it's available. But you can tell the compiler that it's going to be there with the using directive:
template<typename T>
class Derived : public Base<T> {
using Base<T>::a;
void func() {
a++; // OK!
}
};
Alternatively, you can make it explicit that you are using a member of T:
void func {
T::a++; // OK!
}
This one got me upset back then:
#include <vector>
using std::vector;
struct foo {
template<typename U>
void vector();
};
int main() {
foo f;
f.vector<int>(); // ambiguous!
}
The last line in main is ambiguous, because the compiler not only looks up vector within foo, but also as an unqualified name starting from within main. So it finds both std::vector and foo::vector. To fix this, you have to write
f.foo::vector<int>();
GCC does not care about that, and accepts the above code by doing the intuitive thing (calling the member), other compilers do better and warn like comeau:
"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
template "foo::vector" (declared at line 8) used in preference to
class template "std::vector" (declared at line 163 of
"stl_vector.h")
f.vector<int>(); // ambiguous!
The star of questions about templates here on SO: the missing typename!
template <typename T>
class vector
{
public:
typedef T * iterator;
...
};
template <typename T>
void func()
{
vector<T>::iterator it; // this is not correct!
typename vector<T>::iterator it2; // this is correct.
}
The problem here is that vector<T>::iterator is a dependent name: it depends on a template parameter. As a consequence, the compiler does not know that iterator designates a type; we need to tell him with the typename keyword.
The same goes for template inner classes or template member/static functions: they must be disambiguated using the template keyword, as noted in the OP.
template <typename T>
void func()
{
T::staticTemplateFunc<int>(); // ambiguous
T::template staticTemplateFunc<int>(); // ok
T t;
t.memberTemplateFunc<int>(); // ambiguous
t.template memberTemplateFunc<int>(); // ok
}
Out of scope class member function definition:
template <typename T>
class List { // a namespace scope class template
public:
template <typename T2> // a member function template
List (List<T2> const&); // (constructor)
…
};
template <typename T>
template <typename T2>
List<T>::List (List<T2> const& b) // an out-of-class member function
{ // template definition
…
}