Why does this default function argument cause the parser to fail? [duplicate] - c++

Yesterday I ran into a g++ (3.4.6) compiler problem for code that I have been compiling without a problem using the Intel (9.0) compiler. Here's a code snippet that shows what happened:
template<typename A, typename B>
class Foo { };
struct Bar {
void method ( Foo<int,int> const& stuff = Foo<int,int>() );
};
The g++ compiler error is:
foo.cpp:5: error: expected `,' or `...' before '>' token
foo.cpp:5: error: wrong number of template arguments (1, should be 2)
foo.cpp:2: error: provided for `template<class A, class B> struct Foo'
foo.cpp:5: error: default argument missing for parameter 2 of `void Bar::method(const Foo<int, int>&, int)'
Apparently, the default argument is not accepted when written this way, and the compiler assumes that instead of the second template argument a new function argument is specified, for which it then expects a default value because the stuff argument has one. I can help the compiler by creating a typedef, and then everything compiles fine:
template<typename A, typename B>
class Foo { };
struct Bar {
typedef Foo<int,int> FooType;
void method ( FooType const& stuff = FooType() );
};
So I can solve my problem, but I don't understand what is going on. Do I miss a C++ (template?) language feature here and am I doing something wrong, or is the g++ compiler wrong in not accepting the first piece of code?
Note BTW that this also compiles ...
template<typename A, typename B>
class Foo { };
void method ( Foo<int,int> const& stuff = Foo<int,int>() );

I am not so sure that this is a bug in g++ (since version 4.2.4). The code now passes in g++ 4.4 (see UPDATE below). In order to have this code compile for other versions of compilers you can add a set of parenthesis around the default argument:
template<typename A, typename B>
class Foo { };
struct Bar {
void method ( Foo<int,int> const& stuff = ( Foo<int,int>() ) );
};
IMO, these parenthesis are necessary as there is an additional requirement that the default argument can refer to a member of the class that may be declared later in the class body:
struct Bar {
void method ( int i = j); // 'j' not declared yet
static const int j = 0;
};
The above code is legal, and when the declaration for 'method' is being parsed the member 'j' has not yet been seen. The compiler therefore can only parse the default argument using syntax checking only, (ie. matching parenthesis and commas). When g++ is parsing your original declaration, what it is actually seeing is the following:
void method ( Foo<int,int> const& stuff = Foo<int // Arg 1 with dflt.
, int>() ); // Arg 2 - syntax error
Adding the extra set of parenthesis ensures that the default argument is handled correctly.
The following case shows an example where g++ succeeds but Comeau still generates a syntax error:
template<int J, int K>
class Foo { };
struct Bar {
void method ( Foo<0, 0> const & i = ( Foo<j, k> () ) );
static const int j = 0;
static const int k = 0;
};
EDIT:
In response to the comment: "You could just as well have a function call with multiple arguments there", the reason that this does not cause a problem is that the comma's inside the function call are surrounded in parenthesis:
int foo (int, int, int);
struct Bar {
void method ( int j =
foo (0, 0, 0) ); // Comma's here are inside ( )
};
It is possible therefore, to parse this using the syntax of the expression only. In C++, all '(' must be matched with ')' and so this is easy to parse. The reason for the problem here is that '<' does not need to be matched, since it is overloaded in C++ and so can be the less than operator or the start of a template argument list. The following example shows where '<' is used in the default argument and implies the less than operator:
template<int I, int J>
class Foo { };
struct Bar {
template <typename T> struct Y { };
void method ( ::Foo<0,0> const& stuff = Foo<10 , Y < int > = Y<int>() );
struct X {
::Foo<0, 0> operator< (int);
};
static X Foo;
};
The above "Foo<10" is a call to the "operator<" defined in 'X', not the start of the template argument list. Again, Comeau generates syntax errors on the above code and g++ (including 3.2.3) parse this correctly.
FYI, the appropriate references are a note in 8.3.6/5:
[Note: in member function declarations, names in default argument expressions are looked
up as described in 3.4.1...
and then in 3.4.1/8
A name used in the definition of a member function (9.3) of class X following the function’s declaratorid29)
shall be declared in one of the following ways:
...
— shall be a member of class X or be a member of a base class of X (10.2), or
This bullet here, is the part that forces the compiler to "delay" lookup for the meaning of the default argument until all of the class members have been declared.
<UPDATE>
As pointed out by "Employed Russian", g++ 4.4 is now able to parse all of these examples. However, until the DR has been addressed by the C++ standards committee I am not yet ready to call this a "bug". I believe that long term extra parenthesis will be required to ensure portability to other compilers/tools (and maybe even future versions of g++).
It has been my experience that the C++ standard does not dictate that compiler vendors should all use the same parser technology and they also cannot expect that all technologies are equally powerful. As a result, parsing requirements normally don't require that vendors perform superhuman feats. To illustrate this consider the following two examples:
typedef T::TYPE TYPE;
T::TYPE t;
If 'T' is dependent, then given each context 'TYPE' must be a typename, however the standard still requires the typename keyword. These examples are unambiguous and can only mean one thing, however the standard (in order to allow for all parser technologies) still requires the typename keyword.
It's possible that the DR may be addressed in such a way that a compiler which fails to parse these examples will still be "standard conforming" as long as extra parenthesis allows the code to parse.
</UPDATE>

This is a known bug in gcc.
It has been fixed in gcc-4.4, which compiles the original source just fine.

Looks like a compiler bug. I tried it on IBM's xlC compiler V7.0 (which I've found to be more standard-conforming than gcc) and it compiles okay.

template <bool> class A {};
typedef A<static_cast<bool>(1>0)> B;//buggy
int main() { B b; }

Related

Why do MSVC and Clang produce different outputs for the same function template call?

After messing around with concepts I came across something in visual studio that I didn't understand, although I don't know if the issue here is anything to do with concepts specifically. I'm sure there's a reason for this behaviour, but it would be great if someone could explain. There are two parts to this question. For the following snippet:
#include <concepts>
#include <utility>
template <typename PolicyType, typename T, typename... Ts>
concept concept_policy = requires(Ts&&... args)
{
{ PolicyType::template Create<T>(args...) } -> std::same_as<T*>;
};
struct basic_policy
{
template <typename T, typename... Ts>
static T* Create(Ts&&... args)
{
return new T { std::forward<Ts>(args)... };
}
};
struct type_a
{
int m_val;
};
template <concept_policy<int> TPolicy = basic_policy>
static void DoSomething()
{
//works on msvc, msvc needs the "template" for no args, but not with?
{
type_a* type1 = TPolicy::Create<type_a>(5); //why is this fine without template?
type_a* type2 = TPolicy::template Create<type_a>(); //why does this require template if the above doesn't?
}
// //clang requires both to have "template"
// {
// type_a* type1 = TPolicy::template Create<type_a>(5);
// type_a* type2 = TPolicy::template Create<type_a>();
// }
}
int main()
{
DoSomething();
{
//both versions compile fine without "template"
basic_policy policy;
type_a* type1 = basic_policy::Create<type_a>(5);
type_a* type2 = basic_policy::Create<type_a>();
}
return 0;
}
Why do msvc and clang produce different outputs here? Msvc is fine having the "template" omitted for the call with arguments, but not without
Using a similar policy design, is there any way around prefixing the Create with "template"? Ideally I'd like to be able to call TPolicy::Create<type>(...);
Clang is correct: the call to TPolicy::Create<type_a> requires the word template because TPolicy is a dependent type.
Specifically, according to the standard, when we have a fragment of the form T::m< where T is a dependent type other the current instantiation, the compiler must assume that < is the less-than operator, not the beginning of a template argument list. If you mean < as a template argument list, then you must prefix m with the keyword template.
This behaviour is specified in [temp.names]/3. A < that doesn't satisfy any of the conditions listed must be interpreted to mean the less-than operator; the compiler cannot use contextual information to determine that it means the beginning of a template argument list.
As for why MSVC sometimes fails to diagnose the violation, I am not sure.
There is no way to make TPolicy::Create<type>(...); just work without the template keyword. If you really hate writing template, you have to restructure your code so that Create is a non-member, sort of like std::get in the standard library (which would have to be invoked in the form .template get<i>() if it were a class member and the object expression were of dependent type). I guess in this case, Create could be a class template that takes the policy class as one of its template arguments, and the type you want to create as another. I have been told that people often do make their templates into non-members for this exact reason (to avoid having to write template). I think that's a big mistake. It's better to write template than to choose a less natural design.

std::function, literal types and templates

I'm working on C++17 project which among others have these definitions (in my namespace, of course):
using CppFunction = std::function<int(StatePtr&)>;
template<typename T>
using CppMethod = std::function<int(T*, StatePtr&)>;
Now I declare some functions:
template<typename... Targs, typename F>
constexpr CppFunction CppFunctionNative(F func);
template<typename... Targs, typename F, typename T = (deducing class from F here) >
constexpr CppMethod<T> CppMethodNative(F func);
To my surprise, first declaration cause compiler error Constexpr function's return type is not a literal type, but second works just fine.
Why does this happen? Is it related to the fact that second function's return type is template?
UPD: simplified standalone example:
#include <functional>
using CppFunction = std::function<int(int&)>;
template<typename T>
using CppMethod = std::function<int(T*, int&)>;
// Clang will complain
template<typename F>
constexpr CppFunction CppFunctionNative(F func) {};
// Clang will not complain
template<typename F, typename T = /*(deducing class from F here)*/char >
constexpr CppMethod<T> CppMethodNative(F func) {};
// main() function doesn't matter
int main() {
CppFunctionNative(0);
CppMethodNative(0);
return 0;
};
Interestingly enough, OnlineGDB and offline GCC 8.3.0 doesn't complain about this, but my Clang 8 does.
To my surprise, first declaration cause compiler error Constexpr function's return type is not a literal type, but second works just fine.
Why does this happen? Is it related to the fact that second function's return type is template?
Yes. In the first case, the compiler can prove that that specific specialization of std::function is not a literal type.
In the second case, it must know T before it knows if the specific specialization of std::function is a literal type.
template<class T>
struct example {
virtual T get() const {return {};}
~example() {}
};
template<>
struct example<int> {};
#if 0
template<class F>
constexpr example<double> test( F ) { return {}; }
#endif
template<class T, class F>
constexpr example<T> test2( F ) { return {}; }
Live example
test is illegal; test2 is fine. In fact, test2<int>( 3.14 ) is a legal constexpr call.
Now, std::function has no such specialization, but that is not something the compiler is required to prove; doing so in general requires solving the halting problem, which is something C++ standard tries to avoid asking compilers to do.
As mentioned by #MaxLanghof, this kind of error results in an "ill-formed, no diagnostic required" program. The compiler is not forced to detect that your constexpr function cannot be constexpr, but if you do that the compiler is free to do anything, including generate an error message (or worse things).
So GCC is not wrong to omit the error, and clang is not wrong to emit an error. Clang's error emission is, in a sense, a higher QoI than gcc's omission.
Edit: Yakk's answer is more complete - one has to of course consider the theoretical possibility of std::function specializations!
constexpr means "there is at least one set of arguments for which this function produces a constant expression". If no such arguments exist, the program is ill-formed, no diagnostic required. This means it is up to the compiler whether it completely ignores this issue, whether it only complains at instantiation-time or whether it already barks at the declaration.
clang is evidently smart/eager enough to realize that a function template with a non-literal return type can never be constexpr. gcc does not seem to bother checking this - it's not required to. Your program is still wrong though - std::function is not a literal type and can thus never be returned from a constexpr function.

Why is this declaration of a function in template class invalid?

Consider the following code:
template<int X, int Y>
struct S
{
typedef int func(int,float) const;
};
template<int X>
struct D : public S<X,6>
{
typename S<X,6>::func func;
};
template<int X>
int D<X>::func(int,float) const
{
return 1;
}
//----------------
struct W : public S<7,8>
{
S<7,8>::func func;
};
int W::func(int,float) const
{
return 2;
}
#include <iostream>
int main()
{
W w;
std::cout << w.func(1,4.3) << "\n";
D<3> d;
std::cout << d.func(1,4.3) << "\n";
}
If I comment out the code declaring class D and D::func() as well as the corresponding lines in main(), the code compiles normally, and I see 2 in output, as expected.
But when I make the derived class template (adding typename before function declaration, as S<X.6> is a dependent scope), I get the following errors:
test.cpp:13:27: error: no ‘int D<X>::func(int, float) const’ member function declared in class ‘D<X>’
int D<X>::func(int,float) const
^
test.cpp: In instantiation of ‘struct D<3>’:
test.cpp:32:10: required from here
test.cpp:10:27: error: field ‘D<3>::func’ invalidly declared function type
typename S<X,6>::func func;
^
Why can't I declare func in a template derived class, while in non-template class it's OK?
What exactly is "invalidly declared function type"? what is invalid here?
N3337 [dcl.fct]/10: A typedef of function type may be used to declare a function but shall not be used to define a function.
By this rule, both D and W are technically well-formed. I think the reason this doesn't compile with GCC or Clang is that declaring a function with a typedef is really rare. Declaring a function with a member typedef dependent on a template parameter is even rarer. Looks like you've just hit on a dark corner where compiler support is limited.
Funnily enough, MSVC actually does the right thing here.
Your best option is probably to find a different way to express your classes. I can't really give any directed advice without knowing more about the problem you are trying to solve, but if you ask a new question with details we can give some suggestions.
You might also think about filing a bug report for GCC and Clang.
Edit:
However, as Jarod42 pointed out, the dependent type could later be defined as something other than a function type, making the declaration invalid. The reason MSVC works where GCC and Clang does not is the same reason MSVC doesn't require typename in some places: it doesn't correctly implement two-phase lookup. Having this case fully specified would require something like function_typename to mark a dependent name as being a function type. I think declaring a function based on a dependent type is underspecified and inconsistent as a result of this being a very rare case.
As the error message states : In D func is not a member function, thus you cannot provide a definition for it. It is a member with type S<X,6>::func.

Deduce member function return type using a class member function object

Edit: I feel kind of silly now. The posted code actually works with ???=decltype(acc(base(i)))... The error was something else - highly confusing though. I will post a new question about that. Thank you for your help.
I have some code like this:
template<typename Base, typename Acc>
struct Foo
{
Base base;
Acc acc;
auto operator()(unsigned i) const -> decltype(???) // what is ???
{ return acc(base(i)); }
};
How do I get the correct return type?
I tried with decltype(acc(base(i))) but this gives an error (using GCC 4.6.3):
there are no arguments to ‘base’ that depend on a template parameter,
so a declaration of ‘base’ must be available
I have been troubled for hours or days around such problems. Typically gcc wants this-> but clang does not. In some cases Foo:: also helps but there have been cases where I have given up using the member names. The following is only using the type names and (though more verbose) I think will not have any problems with either:
template<typename Base, typename Acc>
struct Foo
{
Base base;
Acc acc;
template<typename S>
using result = typename std::result_of<S>::type;
auto operator()(unsigned i) const
-> result<const Acc(result<const Base(unsigned)>)>
{ return acc(base(i)); }
};
More generally, whenever decltype(member_name) is causing problems, you can safely use decltype(std::declval<member_type>()) where member_type is const-qualified if the member function using it is const.
Even more generally, if you have a member function that is &&, & or const& qualified, use member_type, member_type& or const member_type& respectively in such expressions.
I have never looked into what the standard says but in practice compilers treat expressions differently in trailing return types and inside function definitions when it comes to class members.

C++ syntax ambiguity

Consider:
void f(std::pair<bool,bool> terms = std::pair<bool,bool>(1,1)) {}
gcc 4.4 is ok, gcc 4.3 complains error: expected ',' or '...' before '>' token. The fix is:
void f(std::pair<bool,bool> terms = (std::pair<bool,bool>(1,1))) {}
What's the reason? Is it a bug in 4.3?
This was a known issue. It thinks that the second comma separates parameter declarations. This comes from the fact that in a class definition, function default arguments are first only tokenized, and then only later parsed when the full class body has been read. As it thus doesn't really parse the default argument, it doesn't notice the comma is really a comma within a template argument list instead.
See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#325 for something to read about it. Cited
The other problem is with collecting the tokens that form the default argument expression. Default arguments which contain template-ids with more than one parameter present a difficulty in determining when the default argument finishes. Consider,
template <int A, typename B> struct T { static int i;};
class C {
int Foo (int i = T<1, int>::i);
};
The default argument contains a non-parenthesized comma. Is it required that this comma is seen as part of the default argument expression and not the beginning of another of argument declaration? To accept this as part of the default argument would require name lookup of T (to determine that the '<' was part of a template argument list and not a less-than operator) before C is complete. Furthermore, the more pathological
class D {
int Foo (int i = T<1, int>::i);
template <int A, typename B> struct T {static int i;};
};
would be very hard to accept. Even though T is declared after Foo, T is in scope within Foo's default argument expression.