I try to compile the following C++ code:
struct A {
template< bool x >
bool fun() {
return x;
}
};
template< typename T >
struct B {
struct A2 {
template< bool x >
bool fun() {
return x;
}
};
void test() {
A a;
A2 a2;
a.fun< true >();
a2.fun< true >();
}
};
The compiler complains that:
source_file.cpp: In member function ‘void B<T>::test()’:
source_file.cpp:22:24: error: expected primary-expression before ‘)’ token
a2.fun< true >();
^
However the line just above (a.fun< true >()) compiles just fine. Interestingly, if I remove the line template< typename T >, then compilation succeeds. However that line is required for reasons that do not appear from the minimal (not) working example. What is wrong here?
In this context A2 is actually a shorthand for B<T>::A2. Since A2 is a type dependent on the template parameter T, you have to refer to its member templates with an explicit template keyword
a2.template fun< true >();
A is not a dependent type and its member templates can be referred to with "plain" syntax without that extra template keyword.
See 14.2/4 and a similar example there
14.2 Names of template specializations [temp.names]
4 When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template.
Otherwise the name is assumed to name a non-template. [ Example:
struct X {
template<std::size_t> X* alloc();
template<std::size_t> static X* adjust();
};
template<class T> void f(T* p) {
T* p1 = p->alloc<200>(); // ill-formed: < means less than
T* p2 = p->template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
}
—end example ]
Related
When playing with libstdcxx's test_property:
template<template<typename...> class Property,
typename Type1, typename... Types>
constexpr bool
test_property(typename Property<Type1, Types...>::value_type value)
{
return (Property<Type1, Types...>::value == value
&& Property<Type1, Types...>::type::value == value);
}
class Property accepts at least 1 template parameter(Type1).
Here is a use case:
static_assert(test_property<is_copy_assignable, ExceptMoveAssignClass>(false), "");
But I found clang doesn't work fine with this function:
prog.cc:29:3: error: no matching function for call to 'test_property'
test_property<std::is_copy_assignable, DeletedMoveAssignClass>(false);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:12:1: note: candidate template ignored: substitution failure [with Property = std::is_copy_assignable, Type1 = DeletedMoveAssignClass]: too many template arguments for class template 'is_copy_assignable'
test_property(typename Property<Type1, Types...>::value_type value)
^ ~~~~~~~~
1 error generated.
The root cause is clang doesn't allow class Property to be class that only accepts one template parameter like template< class T > struct is_copy_assignable;. Once class Property is modified into Property<Type1>, it will compile successfully:
template<template<typename...> class Property, typename Type1>
constexpr bool
ya_test_property(typename Property<Type1>::value_type value)
{
return (Property<Type1>::value == value
&& Property<Type1>::type::value == value);
}
here is demo https://wandbox.org/permlink/LlL1o57Yted5WZo5
Of course, this function is from libstdcxx, so gcc can pass compile. Is this clang's bug?
Looks like a Clang bug if I'm interpreting [temp.variadic]/7 correctly:
When N is zero, the instantiation of the expansion produces an empty
list. Such an instantiation does not alter the syntactic
interpretation of the enclosing construct, even in cases where
omitting the list entirely would otherwise be ill-formed or would
result in an ambiguity in the grammar. [ Example:
template<class... T> struct X : T... { };
template<class... T> void f(T... values) {
X<T...> x(values...);
}
template void f<>(); // OK: X<> has no base classes
// x is a variable of type X<> that is value-initialized
— end example ]
Similarly, while std::is_copy_assignable<ExceptMoveAssignClass , > is ill-formed, an empty pack should not put us in this state. It should be equivalent to std::is_copy_assignable<ExceptMoveAssignClass>, which is well-formed.
Of course, if the pack wasn't empty, then we'd be passing too many arguments, which is ill-formed. But that is not the case.
Given the following code,
template <class> using void_t = void;
template <class C, class = void> struct X { enum { v = 0 }; };
template <class C> struct X<C, void_t<typename C::T> > { enum { v = 1 }; };
struct T { };
int main() { return X<T>::v; }
what should main return? GCC and MSVC say 1, Clang says 0.
I think Clang is right here. The rule in [class.qual] is:
In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C:
if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C ([class]), or
[... irrelevant here ...]
the name is instead considered to name the constructor of class C. [ Note: For example, the constructor is not an acceptable lookup result in an elaborated-type-specifier so the constructor would not be used in place of the injected-class-name. — end note ] Such a constructor name shall be used only in the declarator-id of a declaration that names a constructor or in a using-declaration. [ Example:
struct A { A(); };
struct B: public A { B(); };
A::A() { }
B::B() { }
B::A ba; // object of type A
A::A a; // error, A::A is not a type name
struct A::A a2; // object of type A
— end example ]
typename C::T is the same kind of thing as A::A, it's lookup in which function names are not ignored (typename doesn't cause function names to be ignored). So, in typename C::T, when C is T, the name T is considered to name the constructor. As it's not a type name, we should get a substitution failure and fallback to the primary template.
Filed 86818.
To complete Barry's answer, typename only says to the compiler that the following name is a type for the analysis performed before template instatiation. After instantiation, name look up is performed as if typename was not there, [temp.res]/4:
The usual qualified name lookup is used to find the qualified-id even in the presence of typename.
So Clang is right. In order to get a consistent compiler behaviour you can use the elaborated type specifier struct C::T in place of typename C::T:
template <class> using void_t = void;
template <class C, class = void> struct X { enum { v = 0 }; };
template <class C> struct X<C, void_t<struct C::T> > { enum { v = 1 }; };
struct T { };
int main() { return X<T>::v; }
During resolution of an overload of a templated member function of a base class, I observed a different behaviour between g++ (5.2.1-23) and clang (3.8.0), with -std=c++14.
#include <iostream>
#include <type_traits>
struct Base
{
template <typename T>
auto a(T t) -> void {
std::cout<< "False\n";
}
};
template <bool Bool>
struct Derived : public Base
{
using Base::a;
template <typename T, bool B = Bool>
auto a(T t) -> std::enable_if_t<B, void>
{
std::cout<< "True\n";
}
};
int main()
{
Derived<true> d;
d.a(1); // fails with g++, prints "true" with clang
Derived<false> d2;
d2.a(1); // fails with clang++, prints "false" with g++
}
The call to Derived<true>::a fails with g++ with the following message:
test.cc: In function ‘int main()’:
test.cc:28:8: error: call of overloaded ‘a(int)’ is ambiguous
d.a(1);
^
test.cc:18:8: note: candidate: std::enable_if_t<B, void> Derived<Bool>::a(T) [with T = int; bool B = true; bool Bool = true; std::enable_if_t<B, void> = void]
auto a(T t) -> std::enable_if_t<B, void>
^
test.cc:7:8: note: candidate: void Base::a(T) [with T = int]
auto a(T t) -> void {
^
and the call to Derived<false>::a fails with clang++ with the following message:
test.cc:32:6: error: no matching member function for call to 'a'
d2.a(1);
~~~^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/type_traits:2388:44: note: candidate template ignored: disabled by 'enable_if' [with T = int, B = false]
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^
My guess is that they interpret differently the using Base::a;, and that it isn't considered in clang, whereas it's (maybe too much) considered in g++. What I thought would happen is that if Derived has true as parameter, then the call of a() is dispatched to Derived's implementation, whereas if the parameter is false, the call is dispatched to Base::a.
Are they both wrong? Who is right? Who should I submit a bug report to? Can somebody explain what is going on?
Thanks
From 3.3.10/p3 Name hiding [basic.scope.hiding]:
In a member function definition, the declaration of a name at block
scope hides the declaration of a member of the class with the same
name; see 3.3.7. The declaration of a member in a derived class
(Clause 10) hides the declaration of a member of a base class of the
same name; see 10.2
Also 7.3.3/p15 The using declaration [namespace.udecl]:
When a using-declaration brings names from a base class into a derived
class scope, member functions and member function templates in the
derived class override and/or hide member functions and member
function templates with the same name, parameter-type-list (8.3.5),
cv-qualification, and ref-qualifier (if any) in a base class (rather
than conflicting). [ Note: For using-declarations that name a
constructor, see 12.9. — end note ] [Example:
struct B {
virtual void f(int);
virtual void f(char);
void g(int);
void h(int);
};
struct D : B {
using B::f;
void f(int); // OK: D::f(int) overrides B::f(int);
using B::g;
void g(char); // OK
using B::h;
void h(int); // OK: D::h(int) hides B::h(int)
};
void k(D* p)
{
p->f(1); // calls D::f(int)
p->f(’a’); // calls B::f(char)
p->g(1); // calls B::g(int)
p->g(’a’); // calls D::g(char)
}
— end example ]
This is resolved during member name look-up. Thus, it's before template argument deduction. Consequently, as correctly TC mentioned in the comments Base template function is hidden no matter of SFINAE verdict.
Therefore CLANG is correct and GCC is wrong.
Sorry for how complicated the title of this question is; I tried to describe the minimal SSCCE I constructed for this problem.
I have the following code:
#include <iostream>
namespace fizz
{
template<typename... Ts>
class bar
{
public:
template<int I, typename... Us>
friend auto foo(const bar<Us...> &);
private:
int i = 123;
};
template<int I, typename... Ts>
auto foo(const bar<Ts...> & b)
{
return b.i;
}
}
int main()
{
std::cout << fizz::foo<1>(fizz::bar<int, float>{});
}
This code compiles with GCC 5.2 and doesn't with Clang 3.7:
main.cpp:19:18: error: 'i' is a private member of 'fizz::bar<int, float>'
return b.i;
^
main.cpp:25:24: note: in instantiation of function template specialization 'fizz::foo<1, int, float>' requested here
std::cout << fizz::foo<1>(fizz::bar<int, float>{});
^
main.cpp:13:13: note: declared private here
int i = 123;
^
However, if you change the code slightly (although in a way that is not exactly useful for me, since in the real code this would introduce tons of boilerplate):
#include <iostream>
namespace fizz
{
template<typename... Ts>
class bar
{
public:
template<int I, typename... Us>
friend int foo(const bar<Us...> &);
private:
int i = 123;
};
template<int I, typename... Ts>
int foo(const bar<Ts...> & b)
{
return b.i;
}
}
int main()
{
std::cout << fizz::foo<1>(fizz::bar<int, float>{});
}
it suddenly works with that Clang 3.7.
The difference is that in the version of the code that doesn't compile with Clang, the friend function template uses C++14 auto return type deduction, while the working one plainly says it returns int. The same problem also happens with other variants of auto return type deduction, like auto && or const auto &.
Which compiler is right? Please provide some standard quotes to support the answer, since it is quite possible that a bug will need to be filed for one (...hopefully not both) compilers... or a standard defect, if both are right (which wouldn't be the first time).
I believe it's a clang bug. I want to approach it from this direction. What wrinkles does the auto placeholder type add, as compared to having a specified return type? From [dcl.spec.auto]:
The placeholder type can appear with a function declarator in the decl-specifier-seq, type-specifier-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function declarator includes a trailing-return-type (8.3.5), that trailing-return-type specifies the declared return type
of the function. Otherwise, the function declarator shall declare a function. If the declared return type of
the function contains a placeholder type, the return type of the function is deduced from return statements
in the body of the function, if any.
auto can appear in foo's declaration and definition, and is valid.
If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression,
the program is ill-formed. Once a return statement has been seen in a function, however, the return type
deduced from that statement can be used in the rest of the function, including in other return statements. [ Example:
auto n = n; // error, n’s type is unknown
auto f();
void g() { &f; } // error, f’s return type is unknown
auto sum(int i) {
if (i == 1)
return i; // sum’s return type is int
else
return sum(i-1)+i; // OK, sum’s return type has been deduced
}
—end example ]
The first time we need to use determine the type of an expression, the return type of the function will already have been deduced from the return in the definition of foo(), so this is still valid.
Redeclarations or specializations of a function or function template with a declared return type that uses a
placeholder type shall also use that placeholder, not a deduced type.
We're using auto in both places, so we don't violate this rule either.
In short, there are several things that differentiate a specific return type from an placeholder return type from a function declaration. But all the usages of auto in the example are correct, so the namespace-scope foo should be seen as a redeclaration and definition of the first-declared friend auto foo within class template bar. The fact that clang accepts the former as a redeclaration for return type int but not for auto, and there is no relevant different for auto, definitely suggests this is a bug.
Further, if you drop the int I template parameter so that you can call foo unqualified, clang will report the call as ambiguous:
std::cout << foo(fizz::bar<int, float>{});
main.cpp:26:18: error: call to 'foo' is ambiguous
std::cout << foo(fizz::bar<int, float>{});
^~~
main.cpp:10:21: note: candidate function [with Us = <int, float>]
friend auto foo(const bar<Us...> &);
^
main.cpp:17:10: note: candidate function [with Ts = <int, float>]
auto foo(const bar<Ts...>& b)
^
So we have two function templates named foo in the same namespace (since from [namespace.memdef] the friend declaration for foo will place it in the nearest enclosing namespace) that take the same arguments and have the same return type (auto)? That shouldn't be possible.
It appears that your first example should work. There is a statement in C++14 (7.1.6.4 p12):
Redeclarations or specializations of a function or function template with a declared return type that uses a
placeholder type shall also use that placeholder, not a deduced type. [ Example:
.
.
.
template <typename T> struct A {
friend T frf(T);
};
auto frf(int i) { return i; } // not a friend of A<int>
The reason for the example appears to be to explain that to make the declarations match (and cause the defined function to be a friend) the declaration of frf inside struct A would also need to use auto. This implies to me that having a friend declaration with an auto return type and later defining the friend function (and also using auto) is allowed. I can't find anything that would make this work differently for a member function template, like in your example.
This code fails to compile on g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, with this error
test.cpp: In function ‘T mul(V&, V&)’:
test.cpp:38:27: error: expected primary-expression before ‘>’ token
test.cpp:38:29: error: expected primary-expression before ‘)’ token
test.cpp:38:53: error: expected primary-expression before ‘>’ token
test.cpp:38:55: error: expected primary-expression before ‘)’ token
but it compiles and executes correctly on Microsoft C/C++ Optimizing Compiler Version 15.00.21022.08 for x64
#include <iostream>
#include <complex>
template <class T>
class SM
{
public:
T value;
};
template <class T>
class SC : public SM<T>
{
};
class PSSM {
public:
template <class T>
T & getSC() { return sc; }
private:
SC<double> sc;
};
class USSM {
public:
template <class T>
T & getSC() { return sc; }
private:
SC<std::complex<double> > sc;
};
template <class T, class V>
T mul( V & G, V & S) {
return (G.getSC<SC<T> >().value * S.getSC<SC<T> >().value); // error is here
}
int main() {
PSSM p;
PSSM q;
p.getSC<SC<double> >().value = 5;
q.getSC<SC<double> >().value = 3;
std::cout << mul<double>(p,q);
}
I don't understand where the problem is. Can anyone understand how to work around it, or explain the nature of the problem in g++?
The problem is syntactic. You should use the template disambiguator in this case, so that your invocation of a member function template will be correctly parsed:
return (G.template getSC<SC<T> >().value * S.template getSC<SC<T> >().value);
// ^^^^^^^^^ ^^^^^^^^^
This disambiguator helps the compiler recognizing that what follows G. is a member template specialization and not, for instance, a data member called getSC followed by a < (less than).
The Standard reference for the template disambiguator is Paragraph 14.2/4 of the C++11 Standard:
When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.[ Example:
struct X {
template<std::size_t> X* alloc();
template<std::size_t> static X* adjust();
};
template<class T> void f(T* p) {
T* p1 = p->alloc<200>(); // ill-formed: < means less than
T* p2 = p->template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
}
—end example ]