friend method from a template specializated struct: g++ and clang++ different behaviour - c++

Trying to propose a solution to another question, I bumped (again) my nose against code that compile and work with clang++ (3.5) but give compilation error with g++ (4.9.2)
The following is a simplified minimal (I hope) example
#include <iostream>
class foo;
template <std::size_t>
struct bar;
template <>
struct bar<0U>
{ static void baz (foo const & f); };
class foo
{
int i = 42;
template <std::size_t I>
friend void bar<I>::baz (foo const &);
};
void bar<0U>::baz (foo const & f)
{ std::cout << f.i << std::endl; }
int main()
{
foo f;
bar<0U>::baz(f);
}
The error from my g++ is
test_114-98,11,14,clang.cpp:18:41: error: member ‘void bar<<anonymous> >::baz(const foo&)’ declared as friend before type ‘bar<<anonymous> >’ defined
friend void bar<I>::baz (foo const &);
^
test_114-98,11,14,clang.cpp: In static member function ‘static void bar<0ul>::baz(const foo&)’:
test_114-98,11,14,clang.cpp:15:13: error: ‘int foo::i’ is private
int i = 42;
^
test_114-98,11,14,clang.cpp:22:19: error: within this context
{ std::cout << f.i << std::endl; }
^
My question, as usual, is: who's right and who's wrong.

Related

How to call function template from another function defined earlier?

I have two function templates A and B. I define A and then B in the same file. Now I would like to call B in A. How can I realize this? Normal function prototype doesn't work in this case. (Please assume you cannot change the order of A and B or split files.)
#include <iostream>
template <class Type>
Type A(Type x) {
return 2 * B(x);
}
template <class Type>
Type B(Type x) {
return 3 * x;
}
int main() {
int x = 3;
std::cout << A(x) << "\n"; //=> ERROR
}
ERROR from g++:
test.cpp: In instantiation of ‘Type A(Type) [with Type = int]’:
test.cpp:40:21: required from here
test.cpp:29:17: error: ‘B’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
return 2 * B(x);
~^~~
test.cpp:33:6: note: ‘template<class Type> Type B(Type)’ declared here, later in the translation unit
Type B(Type x) {
^
If by prototype you mean declaration, it certainly does work in this case!
You can declare a function template just fine:
#include <iostream>
// Non-defining declaration B
template <class Type>
Type B(Type x);
// Defining declaration A
template <class Type>
Type A(Type x) {
return 2 * B(x);
}
// Defining declaration B
template <class Type>
Type B(Type x) {
return 3 * x;
}
int main() {
int x = 3;
std::cout << A(x) << "\n"; //=> NO ERROR
}
(live demo)

C++ template name binding in gcc-6.3.0

I learn the C++ template name binding and instantiation recently, and find the strange behavious in the following code.
#include <iostream>
using namespace std;
template <typename T>
int f(T a)
{
return g(a); // g() should be dependent name
}
struct C {};
int g(C c)
{
return 0;
}
int g(int i)
{
return i;
}
int main()
{
// Works!
int z = f(C{});
// Error: no declarations were found by argument-dependent lookup at the point of instantiation
//int z = f(10);
cout << z << endl;
return 0;
}
I think g(T) should be dependent name and int z = f(10) should work like int z = f(C{}). But gcc-6.3.0 complains:
g++ -g -o tmpl tmpl.cpp
tmpl.cpp: In instantiation of ‘int f(T) [with T = int]’:
tmpl.cpp:29:17: required from here
tmpl.cpp:8:13: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
return g(a);
~^~~
tmpl.cpp:18:5: note: ‘int g(int)’ declared here, later in the translation unit
int g(int i)

C++ template specialization for pointer?

I read book < C++ Templates - the Complete Guide > and learned template specialization for pointer. (maybe I misunderstand this part of the book)
(1) Here's my simple template:
#include <iostream>
template<typename T>
void Function(const T& a)
{
std::cout << "Function<T>: " << a << std::endl;
}
template<typename T>
void Function<T*>(const T* a)
{
std::cout << "Function<T*>: " << a << std::endl;
}
int main(void)
{
Function(1);
Function(1.2);
Function("hello");
Function((void*)0x25);
return 0;
}
I use ubuntu16.04 x64, g++ 5.3, the compiler report:
$ g++ main.cpp -o main.exe
main.cpp:10:29: error: non-type partial specialization ‘Function<T*>’ is not allowed
void Function<T*>(const T* a)
(2) but this code is correct:
#include <iostream>
template<typename T>
void Function(const T& a)
{
std::cout << "Function<T>: " << a << std::endl;
}
int main(void)
{
Function(1);
Function(1.2);
Function("hello");
Function((void*)0x25);
return 0;
}
result shows:
$ g++ main.cpp -o main.exe
$ ./main.exe
Function<T>: 1
Function<T>: 1.2
Function<T>: hello
Function<T>: 0x25
My question is: Is the book about pointer specialization is wrong ? Or I mis understand the meaning of this part in the book ? Or something else ?
Update about pointer specialization in class.
(3) template class with pointer specialization:
#include <iostream>
template<typename T>
struct Base {
T member;
Base(const T& a)
: member(a)
{
}
void hello()
{
std::cout << member << std::endl;
}
};
template<typename T>
struct Base<T*> {
T* member;
Base(T* a)
: member(a)
{
}
void hello()
{
std::cout << member << std::endl;
}
};
int main(void)
{
Base<int> b1(12);
Base<double> b2(2.4);
Base<char*> b3("hello");
Base<void*> b4((void*)0x25);
b1.hello();
b2.hello();
b3.hello();
b4.hello();
return 0;
}
this code is correct with one warning:
$ g++ main.cpp -o main.exe
main.cpp: In function ‘int main()’:
main.cpp:37:27: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Base<char*> b3("hello");
^
$ ./main.exe
12
2.4
hello
0x25
(4) template class without pointer specialization:
#include <iostream>
template<typename T>
struct Base {
T member;
Base(const T& a)
: member(a)
{
}
void hello()
{
std::cout << member << std::endl;
}
};
int main(void)
{
Base<int> b1(12);
Base<double> b2(2.4);
Base<char*> b3("hello");
Base<void*> b4((void*)0x25);
b1.hello();
b2.hello();
b3.hello();
b4.hello();
return 0;
}
result is the same:
$ g++ main.cpp -o main.exe
main.cpp: In function ‘int main()’:
main.cpp:39:27: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Base<char*> b3("hello");
^
$ ./main.exe
12
2.4
hello
0x25
Does this means pointer specialization is needless ?
Or maybe this feature behave differently on different compiler ?
as you've been already told, partial specialization of function templates are not allowed. You can use std::enable_if for this:
template <typename T, typename std::enable_if_t<!std::is_pointer<T>::value>* = 0>
void func(T val) { std::cout << val << std::endl; }
template <typename T, typename std::enable_if_t<std::is_pointer<T>::value>* = 0>
void func(T val) { func(*val); }
If you are looking for simpler syntax, wait for concepts
The error message told you what is wrong:
non-type partial specialization ‘Function<T*>’ is not allowed
You can only partially specialize types (classes). You've tried to partially specialize a function. Functions are not types; you can only fully specialize them.
Two problems:
You are not allowed to partially specialise a function.
The behaviour of (void*)0x25 is undefined. With the exception of nullptr, you are not allowed to set a pointer to memory you don't own, with the exception of one past the final element of an array and one past the address of a scalar.

Clang++-3.7 CRTP compilation error "no named member" in parent's template argument

In the below code I am trying to use CRTP to use the static member "value" from the Child class in the Parent class. When compiling the code with g++ 5.2.1 with the "-pedantic" flag, I am able to compile as expected, and on execution both c.print_value(); and Child<int,4>::print_value(); print out 4.
#include <iostream>
template <typename DE>
struct Parent
{
static const int value = DE::value;
static void print_value ()
{
std::cout << "Value : " << value << '\n';
}
};
template <typename T, int N>
struct Child : Parent< Child<T,N> >
{
static const int value = N;
};
int
main ()
{
Child<int,4> c;
c.print_value();
Child<int,4>::print_value();
}
However when compiling the same code with clang++3.7, I encounter compilation failures.
crtp_clang_error.cpp:9:32: error: no member named 'value' in 'Child<int, 4>'
static const int value = DE::value;
~~~~^
crtp_clang_error.cpp:27:16: note: in instantiation of template class 'Parent<Child<int, 4> >' requested here
struct Child : Parent< Child<T,N> >
^
crtp_clang_error.cpp:38:16: note: in instantiation of template class 'Child<int, 4>' requested here
Child<int,4> c;
^
crtp_clang_error.cpp:40:3: error: no member named 'print_value' in 'Child<int, 4>'; did you mean 'Parent<Child<int, 4> >::print_value'?
Child<int,4>::print_value();
^~~~~~~~~~~~~~~~~~~~~~~~~
Parent<Child<int, 4> >::print_value
crtp_clang_error.cpp:11:15: note: 'Parent<Child<int, 4> >::print_value' declared here
static void print_value ()
I am not sure if this a Clang++ bug or a GCC hack. Would very much appreciate some insights.

Why are cv-qualifiers in template parameters ignored?

I had some code that was failing to compile, which amounts to something
like what's shown below. After some digging around, I came across
paragraph 14.1 note 5, which states:
The top-level cv-qualifiers on the template-parameter are ignored
when determining its type.
My code looks like this:
#include <iostream>
#include <typeinfo>
class Bar {};
template<class T>
void Func(T t)
{
std::cout << typeid(T).name() << "\n";
}
template<class T>
void Func(const T& t)
{
std::cout << "const ref : " << typeid(T).name() << "\n";
}
int main()
{
Bar bar;
const Bar& constBar = bar;
Func(constBar);
return 0;
}
It gives this compilation error:
In function 'int main()'
error: call of overloaded 'Func(const Bar&)' is ambiguous
Can someone comment on the reasoning behind the this rule in the standard?
The problem with your code is that the function call is ambiguous. The const Bar & can match either the value or the const reference. G++ says:
xx.cpp:24: error: call of overloaded 'Func(const Bar&)' is ambiguous
This has nothing specifically to do with templates - you would get the same error if you overloaded a non-template function.
And as people have told you here time after time, you will not learn C++ by reading the Standard.
As you could have found easily yourself, this has nothing to do with templates. This
class Bar {};
void Func(Bar) {}
void Func(const Bar&) {}
int main()
{
Bar bar;
const Bar& constBar = bar;
Func(bar);
Func(constBar);
return 0;
}
gives the same errors.
The call is ambiguous because anything can match T or const T &.
Just try Func(0);: it will give the same error message.