using declaration: one more bug of gcc and clang? - c++

Why do gcc HEAD 10.0.0 20190 and Clang HEAD 9.0.0 both reject this program?
#include <iostream>
void g( int x )
{
std::cout << "Hello g( " << x << " )\n";
}
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
namespace N
{
using ::g;
}
void g( int x = 20 );
template <int N = 10>
void g();
int main()
{
N::g();
N::g<>();
}
For example gcc issues the error
prog.cc: In function 'int main()':
prog.cc:27:11: error: no matching function for call to 'g()'
27 | N::g<>();
| ^
prog.cc:9:6: note: candidate: 'template<int N> void g()'
9 | void g()
| ^
prog.cc:9:6: note: template argument deduction/substitution failed:
prog.cc:27:11: note: couldn't deduce template parameter 'N'
27 | N::g<>();
| ^
though according to the C++ 20 (and 17) Standard (9.8 The using declaration)
11 [Note: For a using-declaration whose nested-name-specifier names a
namespace, members added to the namespace after the using-declaration
are not in the set of introduced declarations, so they are not
considered when a use of the name is made. Thus, additional overloads
added after the using-declaration are ignored, but default function
arguments (9.2.3.6), default template arguments (13.1), and template
specializations (13.6.5, 13.8.3) are considered. — end note]
Based on my reading of the standard, I believe this is a bug.

This issue is the subject of Core issue 1907. The current direction is to treat such cases as ill-formed, no diagnostic required.
As it turns out, some implementations track default arguments on a "per-entity" basis (so it would be difficult to not consider default arguments added in a later redeclaration), while others track them on a "per-declaration" basis (so it would difficult to make them consider such default arguments). CWG decided to accommodate both implementation strategies by classifying code that depends on such things IFNDR.

I think the problem is that you're re-declaring the g<int> template function after implicitly declaring it during its definition.
This minimised example also fails to compile. Note no namespaces involved:
#include <iostream>
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
// redeclaration
template <int N = 10>
void g();
int main()
{
g<>();
}
whereas this compiles:
#include <iostream>
// declaration
template <int N = 10>
void g();
// definition
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
int main()
{
g<>();
}

Related

Usage of concepts with non-type template parameter packs in boolean contexts

In C++20, I defined a concept AllIntegral with a non-type template parameter pack auto... T_values.
Whilst, GCC 10.1.0 accepts its usage in some contexts, it refuses to compile its usage in others, particularly in an
if statement. The associated error message says 'AllIntegral' does not constrain a type.
My code looks like this:
#include <concepts>
#include <ios>
#include <iostream>
template<auto... T_values>
concept AllIntegral = (std::integral<decltype(T_values)> && ...);
int main()
{
std::cout << std::boolalpha << AllIntegral<1, 2> << '\n'; // compiles and prints "true"
if (AllIntegral<1, 2>) std::cout << "true" << '\n'; // does not compile
std::cout.flush();
}
This is the compiler output:
main.cpp: In function ‘int main()’:
main.cpp:11:9: error: ‘AllIntegral’ does not constrain a type
11 | if (AllIntegral<1, 2>) std::cout << "true" << '\n';
| ^~~~~~~~~~~~~~~~~
main.cpp:6:9: note: concept defined here
6 | concept AllIntegral = (std::integral<decltype(T_values)> && ...);
What's the reason for this error? Why is my concept not usable in a boolean context?

Why this code snippet works with C++17 whereas the compiler complains when using C++11?

Why this code snippet works with C++17 whereas the compiler complains when using C++11(i.e https://godbolt.org/z/71G91P)?
Are there any potential problems with this code snippet?
#include<iostream>
class ctx
{
public:
int map_create(void*){std::cout << "haha" << std::endl; return 0;};
};
ctx obj;
typedef int (ctx::*ctx_mem_func)(void*);
template <ctx_mem_func func>
int regHelper(void*)
{
((&obj)->*func)(nullptr);
return 0;
}
constexpr ctx_mem_func testFunc = &ctx::map_create;
typedef int(*callBackFunc)(void*);
int reg(callBackFunc)
{
return 0;
}
int main()
{
reg(regHelper<testFunc>);
//But this expression is ok.
reg(regHelper<&ctx::map_create>);
std::cout << "this is a test" << std::endl;
}
Here are the error messages when using c++11(gun 10.0.2):
<source>: In function 'int main()':
<source>:30:28: error: no matches converting function 'regHelper' to type 'callBackFunc {aka int (*)(void*)}'
reg(regHelper<testFunc>);
^
<source>:13:5: note: candidate is: template<int (ctx::* func)(void*)> int regHelper(void*)
int regHelper(void*)
^
This is a difference between C++14 and C++17. Simplified:
int f();
template<int (&)()> struct S {};
constexpr auto& q = f;
using R = S<q>; // valid in C++17, invalid in C++14
The change is to Allow constant evaluation for all non-type template arguments, meaning that now a constexpr variable naming a function (member function, etc.) is permissible as an NTTP where previously only the actual name of the function was permitted.

g++ and clang++ different behaviour with SFINAE and SFINAE failure

A couple of questions for C++11 experts.
I'm fighting with SFINAE and I came across a strange case in which g++ (4.9.2), and clang++ (3.5.0) behave differently.
I have prepared the following sample code. I'm sorry but I'm unable to do it significantly more concise.
#include <string>
#include <iostream>
#include <typeinfo>
#include <type_traits>
template <typename X>
class foo
{
private:
template <typename R>
using enableIfIsInt
= typename std::enable_if<std::is_same<X, int>::value, R>::type;
public:
foo ()
{ }
template <typename R = void>
enableIfIsInt<R> bar ()
{ std::cout << "bar: is int\n"; }
void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n";
}
};
int main ()
{
foo<long> fl;
foo<int> fi;
fl.bar();
fi.bar();
return 0;
}
My idea was to create a template foo<X> class that (via SFINAE) can define a method in one or in another way depending on the X template argument.
The program compile well with g++ 4.9.2 but clang++ 3.5.0 give the following error
test.cpp:13:36: error: no type named 'type' in
'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable
this declaration
= typename std::enable_if<std::is_same<X, int>::value, R>::type;
^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:26:23: note: in instantiation of template type
alias 'enableIfIsInt' requested here
<< typeid(enableIfIsInt<void>).name() << "}\n";
^
test.cpp:36:7: note: in instantiation of member function
'foo<long>::bar' requested here
fl.bar();
^
1 error generated.
I suppose that is right clang++ but my first question to C++11 experts is: who right? g++ or clang++?
About the g++ produced program output, it's the following
bar: isn't int; is [i]{v}
so g++ seems to ignore the fl.bar(); instruction.
Now a little change: i modify the second version of foo<X>::bar() in this way
void bar ()
{ std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n"; }
deleting the std::enable_if inside the function abomination. Now both g++ and clang++ are compiling without problems and the output, for both compiled versions of the program, is
bar: isn't int; is [l]
bar: isn't int; is [i]
So, my second question is: what I'm doing wrong? Why, in the int case, I don't obtain the "is int" version of foo<X>::bar()?
Be patient with me if I'm doing some foolish: I'm trying to learn C++11.
And sorry for my bad English.
clang's error isn't coming from the substitution failure. It's coming from here:
void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n"; // <==
}
enableIfIsInt<void> isn't in the immediate context, that's a hard failure for X is not int. You simply can't use that expression in that context.
Once you remove that - the non-template bar() is always called. That's because both functions are equivalent matches and non-templates are preferred to templates in overload resolution.
So the real solution is to use tag-dispatching:
void bar() { bar(std::is_same<X, int>{}); }
void bar(std::true_type ) {
std::cout << "bar: is int\n";
}
void bar(std::false_type ) {
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n";
}
with which both compilers happily yield:
bar: isn't int; is [l]
bar: is int

Is g++ misbehaving with function template overloading?

I took the following example from http://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading
and clang (3.4) seems to be handling it just fine, while g++ (4.8.3) gives an 'ambiguous overload' error:
struct A {};
template<class T> struct B {
template<class R> void operator*(R&){ cout << "1" << endl; } // #1
};
template<class T, class R> void operator*(T&, R&) { cout << "2" << endl;} // #2
int main() {
A a;
B<A> b;
b * a; //prints 1
}
clang correctly prints 1 (as expected according to cppreference), while g++ gives this error:
test_templates.cpp: In function ‘int main()’:
test_templates.cpp:13:5: error: ambiguous overload for ‘operator*’ (operand types are ‘B<A>’ and ‘A’)
b * a; //prints 1
^
test_templates.cpp:13:5: note: candidates are:
test_templates.cpp:7:26: note: void B<T>::operator*(R&) [with R = A; T = A]
template<class R> void operator*(R&){ cout << "1" << endl; } // #1
^
test_templates.cpp:9:33: note: void operator*(T&, R&) [with T = B<A>; R = A]
template<class T, class R> void operator*(T&, R&) { cout << "2" << endl;} // #2
Is g++ actually misbehaving here?
This example is taken from the standard (this is the draft for c++11).
14.5.6.2 Partial ordering of function templates paragraph 3 example:
struct A { };
template<class T> struct B {
template<class R> int operator*(R&); // #1
};
template<class T, class R> int operator*(T&, R&); // #2
// The declaration of B::operator* is transformed into the equivalent of
// template<class R> int operator*(B<A>&, R&); // #1a
int main() {
A a;
B<A> b;
b * a; // calls #1a
}
So, the standard itself pretty much say this is legal code. I could copy-paste rules, but one might as well click link and jump to the relevant place. My point is only to prove this is a proper compilable code as defined by the standard.
For what it's worth on my debian clang 3.5.0 compiled it right away, clang 3.4.2 had to be executed with -std=c++11, g++ 4.9.1 reported ambiguity in all cases (I even tried 1y).
I am puzzled by clang behaviour, though. I thought it might have been ambiguous in earlier versions of c++, the rule to disambiguate was added as a part of c++11 and g++ didn't keep up. But clang 3.5 compiles it even with -std=c++98.
That call is ambiguos. GCC is right.
§13.5.2/1
Thus, for any binary operator #, x#y can be interpas either
x.operator#(y) or operator#(x,y). If both forms of the operator
function have been declthe rules in 13.3.1.2 determine which, if any,
interpretation is used.
And in this case, we do have both the member and nonmember function. The built-in version is not included because the left hand operator has class type.
If you called the operator explicitly, there would be no ambiguity. However, when the call is done through an operator (thus implicitly) there is nothing which can distinguish between member and nonmember, therefore they're both viable functions which, in this case, leads to an ambiguous function call.
Previous versions of clang report it as ambiguous as well: http://goo.gl/OWsJUv

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.