I have code of the following structure (which is of course much more complex in reality, especially "Base" is a three-liner, but I've tried to capture the gist of it):
template <class T>
class A {};
template <class T>
class B {
public:
B(){};
};
template <class T>
class C : public B<A<T>> {
public:
using Base = B<A<T>>;
using Base::B;
};
static const C<int> c{};
The code compiles fine with g++ via
g++ -c test.cpp -std=c++11
However, with clang++ I get an error message I don't really understand
clang++ -c test.cpp -std=c++11
test.cpp:14:14: error: dependent using declaration resolved to type without 'typename'
using Base::B;
Is there anything wrong with my code or is this a bug in clang?
Note: When writing using B<A<T>>::B; it compiles fine with both compilers, but this not a real solution to my problem.
Edit: clang version is 3.5.0, gcc version is 4.9.2
From section 12.1:
Constructors do not have names
So the usual rules for qualified lookup do not apply. Instead you have to rely on the special rule for constructor lookup (section 3.4.3.1):
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, or
— in a using-declaration (7.3.3) that is a member-declaration, if the name specified after the nested-name-specifier is the same as the identifier or the simple-template-id’s template-name in the last component of the nested-name-specifier,
the name is instead considered to name the constructor of class C.
So you can certainly write
using Base::Base;
instead of
using Base::B;
Your original version should work under the first bullet point, but injected-class-names get complicated when templates are involved. Just go with the simpler version Base::Base, which additionally is more readable. Anyone who sees that instantly knows you are naming a constructor.
This case has been discussed in the C++ committee (according to Richard Smith https://llvm.org/bugs/show_bug.cgi?id=23107#c1) and things have gotten clearer now:
using Base::B
is not intended to be valid code.
The following method is the correct way to express constructor inheritance when introducing a class alias Base:
using Base::Base
However, the error messages produced by clang are misleading and will hopefully be solved as part of this bug report (https://llvm.org/bugs/show_bug.cgi?id=22242).
Related
I have a problem with compiling boost.bimap library. My test program is a blank main function and only one include directive(like #include <boost/bimap.hpp>).
After some investigations I found out that preprocessor had made some interesting constructions from header file like:
struct A { struct B{}; struct B; };
I don't know if this is correct or not, but gcc accepts it while clang and icc don't. Who is right and what can I do to compile programs with bimap library? Unfortunately, I can't use gcc in this case.
struct B{}; defines a nested class, then struct B; is a re-declaration of the same nested class.
GCC is wrong to accept the code (bug report), because the standard says in [class.mem]:
A member shall not be declared twice in the member-specification, except that a nested class or member class template can be declared and then later defined,
In your case the nested class is defined then declared, which is not allowed, so Clang and ICC are correct to give a diagnostic. However, when I test it they only give a warning, not an error, so maybe you are using -Werror, in which case stop doing that and the code should compile.
The problem in the Boost.Bimap code is a known bug.
I'm trying to figure out whether to file a bug report against Clang, GCC, or both (I've tested against Clang trunk and GCC 4.7.2: if someone could verify this against GCC trunk that would be helpful):
Basically, the following code three-line file compiles fine with -fsyntax-only, in default and C++11 modes:
class A {
friend void f();
};
Note that there's no prior declaration of f(), but this is explicitly OK.
However, Clang (but not GCC) rejects the following:
class A {
friend void ::f();
};
The error from Clang is "no function named 'f' with type 'void ()' was found in the specified scope", but I can't find any justification in the standard for treating this case differently than the previous one, so I think it's a bug; I might be wrong though (I'm reading from N3242, however, which AFAIK is the last public draft before C++11).
This next example, however, is rejected by GCC rather than Clang:
void f() { }
void g()
{
class A {
friend void ::f();
};
}
The error from GCC is "friend declaration ‘void f()’ in local class without prior declaration", which doesn't seem to make sense since void ::f() should refer to the f() in the global namespace, which is declared. (Never mind that friend-ing a global function from a local class is nonsensical, it doesn't seem to be illegal...)
Finally, this last example is rejected both by Clang and GCC:
void g()
{
class A {
friend void ::f();
};
}
The errors are "friend declaration ‘void f()’ in local class without prior declaration" and "no function named 'f' with type 'void ()' was found in the specified scope", respectively. Now, there does appear to be some justification for rejecting a friend declaration of a previously undeclared function in a local class, from 11.4p11, but the paragraph actually reads:
If a friend declaration appears in a local class (9.8) and the name specified is an unqualified name, a prior
declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope.
For a friend function declaration, if there is no prior declaration, the program is ill-formed...
The illegality of this declaration apparently is based on the second sentence in this paragraph, but it's unclear to me whether the sentence should apply in the case of a qualified name as well, as is used in this case. (Arguably, it could be that the entire paragraph applies to the "local class" case regardless of whether or not an "unqualified name" is used, and the "and the name specified is an unqualified name" clause only applies to the lookup described in the first sentence, but it seems like a stretch...the only reason I'm imagining this as a possibility is because both compilers reject it.)
Anyway, so from what I can tell, all four of these cases (regardless of how sensible they are or not) should be legal; even if not, at least one of Clang and GCC is wrong in the second and third cases. Can anyone find an error in my logic?
The third and fourth cases are admittedly nonsensical; but I can see the second case breaking someone's valid and useful code so I'm somewhat surprised it's never been caught, if it is indeed a bug.
I think this sentence from 8.3/1 is relevant:
When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace (7.3.1)) or to a specialization thereof; the member shall not merely have been introduced by a using-declaration in the scope of the class or namespace nominated by the nested-name-specifier of the declarator-id.
The paragraph is talking about declarators in general, in any type of declaration. So I think examples 2 and 4 are ill-formed, clang is correct, and gcc is wrong.
(Example 3 might become more realistic if the global declaration were a template function. It might be useful to friend a global function template or a specialization from a local class. And if that's allowed, your example 3 as written might as well be legal for consistency.)
The following:
template <int A>
class __declspec(align(A)) alignable {
};
Does not compile with Visual Studio, but works fine with GNU (using __attribute__ instead of __declspec). The compiler doesn't seem to be able to resolve the template parameter A when used as part of the class declaration, gives the error "C2059: syntax error: identifier".
I'm beginning to wonder whether this is valid C++, since A is being used within the same statement that it is declared. What puzzles me is that GNU allows this; I've been through the "Templates" section of the standard, but can't seem to find anything explicit about this.
Edit: Since a class can derive from one of its template parameters, it would seem sensible to me that template parameters are available in the class declaration.
I'm trying to port my own lib from Visual Studio to g++ on GNU/Linux, and I'm getting some problems with template compilation. Indeed, in Visual C++, templates are generated only when they are explicitly used in the code, while it seems (from my errors) that g++ evaluates the contents of templates before they are first used. This results in the following error:
error: incomplete type ‘X’ used in nested name specifier
... because I include some classes after the template code, rather than before. I am doing this due to a cross-use conflict.
To sum it seems that Visual C++ does not attempt to resolve templates' content on use, and g++ does resolution as soon as possible.
class MyClass;
template<class _Ty>
void func(MyClass* a_pArg)
{
a_pArg->foo();
};
(_Ty isn't used but it doesn't matter, it's just to explain the problem)
In that case Visual C++ would compile (even if MyClass isn't predeclared), while g++ will not, because MyClass hasn't been completely declared.
Is there a way to tell g++ to instantiate templates only on use?
No, that's the way two-phase lookup works. MSVC implements it wrong, it nearly skips the first phase, which parses the template at the point of definition. MSVC only does some basic syntax checking here. In the second phase, on actual use of the template, the dependent names should only be inspected. MSVC does all kind of parsing here instead. GCC implements the two-phase lookup correctly.
In your case, since MyClass isn't a template parameter, it can inspect it in phase one. You just need to include your class header before that.
As it was indicated in another answer, gcc is correct looking up non-dependent names in the first lookup phase, and VC++ shifts most checks to the second phase (which is incorrect). In order to fix your code, you don't need to search for some broken version of gcc. You need to separate the declaration and implementation (at least for non-dependent names). Using your example,
// provide declarations
class MyClass;
template<class T>
void func(MyClass* a_pArg);
// provide definition of MyClass
class MyClass
{
// watever
};
// provide definition of func
template<class T>
void func(MyClass* a_pArg);
{
a_pArg->foo();
};
If you are willing to use CLang instead of gcc, CLang support the -fdelayed-template (dedicated to perform template instantiation at the end of the parsing) implied by -fms-extensions option specifically designed to compile MSVC code (and numerous quirks).
According to Francois Pichet, who is leading CLang effort to fully compile MSVC code (and actually doing most of it), CLang should be able to parse all of MFC code in about 2 to 3 months, with only a couple of non-trivial issues remaining. Already most of MFC is correctly interpreted (ie, interpreted as VC++ does).
Visual C++ doesn't implement by default two-phase lookup specified by the standard.
However, looks like two-phase lookup is a bit better in Visual Studio 2015 with /Za option. Perhaps you can do the opposite by adding /Za option to mimic GCC template instantiation behavior for some cases.
namespace A{
int i;
}
int main(){
using A::i;
using A::i;
}
VS2010 - compiles fine
gcc (ideone) - compiles fine
Comeau - gives error ""ComeauTest.c", line 10: error: "i" has already been declared in the current scope
using A::i;"
$7.3.3/8 - "A using-declaration is a
declaration and can therefore be used
repeatedly where (and only where)
multiple declarations are allowed."
The example right there indicates that the code is indeed ill-formed.
So, is this a bug in GCC and VS2010?
EDIT 2:
Remove the multiple using directives as it was unrelated to the query on hand.
The example you refer to is known to be inconsistent. The committee hasn't yet fixed this.
So, is this a bug in GCC and VS2010?
I don't think it's a bug in either of GCC/VS2010/Clang or Comeau. It appears to be a bug in the C++ Standard. In these cases, compile writers have to make up their mind on what is most viable. If you remove the example in question, then 3.3/4 states the example is valid: "Given a set of declarations in a single declarative region, each of which specifies the same unqualified name, ... they shall all refer to the same entity, or all refer to functions and function templates; or ...".
The question arises, as discussed in the linked issue, what 7.3.3/8 refers to when it says "declarations", which the committee didn't reach consensus about. And so, until then 3.3/4 applies for GCC/VS2010 and Clang, while Comeau chooses to use some other semantics.
Yes you are right. This is indeed a bug in g++, MSVC++ and Clang. Comeau has got it correct.
As you said 7.3.3/8 says
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple declarations are allowed
The following code snippet is also given.
void f()
{
using A::i;
using A::i; //error: double declaration
}
Similarly your code is ill-formed too.