Is it legal to re-declare a member class after defining it? - c++

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.

Related

A 'using' statement compiles with g++, fails compilation with clang

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).

implicit instantiation of undefined template: Boost Bug or Clang Bug?

I was trying to compile some code that uses Boost (1.49), with Clang(& libc++) from trunk.
The problematic code boils down to the following:
#include <memory>
#include <boost/signals2.hpp>
int main()
{
std::shared_ptr<int> s;
}
When compiled with Clang, the following message is emmited:
$ clang++ -I/home/alexander/usr/local/include --stdlib=libc++ -std=c++0x signals2-bug.cpp -o signals2-bug
signals2-bug.cpp:6:26: error: implicit instantiation of undefined template
'std::shared_ptr<int>'
std::shared_ptr<int> s;
^
/home/alexander/usr/local/include/boost/signals2/detail/foreign_ptr.hpp:24:30: note:
template is declared here
template<typename T> class shared_ptr;
^
The offending lines in boost/signals2/detail/foreign_ptr.hpp are:
#if !defined(BOOST_INTEL_STDCXX0X)
namespace std
{
template<typename T> class shared_ptr;
template<typename T> class weak_ptr;
}
#endif
Now who's to blame?
Two things come to mind:
Why does the Boost.Signals header feel the need to declare an own shared_ptr? What's the gain?
The line in Boost.Signals looks like a simple forward declaration. Why would that be problematic, if it comes after the template definition?
EDIT
This appears to be a Boost.Signals2 bug, because the declaration of things in the std:: namespace results in undefined behaviour, according to the ISO/IEC C++ 2011 Standard, section 17.6.4.2.1:
The behavior of a C++ program is undefined if it adds declarations or
definitions to namespace std or to a namespace within namespace std
unless otherwise specified. A program may add a template
specialization
for any standard library template to namespace std only if the declaration depends on a user-defined type
and the specialization meets the standard library requirements for the original template and is not explicitly
prohibited.
A ticket in the Boost bug tracker has been created: https://svn.boost.org/trac/boost/ticket/6655
Please note, that a Clang bug also exists here: http://llvm.org/bugs/show_bug.cgi?id=10521 , however the implementor points to violation.
Follow-up for Googlers:
The problem was indeed a Boost bug. This changeset 77289 should fix the issue for Boost 1.50.
The corresponding Bug in Clang was marked invalid.
The code in foreign_ptr.hpp is a redeclaration (if shared_ptr has already been defined), and as such not likely to cause problems (adding declarations to std is technically undefined behavior, but most compilers don't care since they don't really distinguish between standard library headers and other files). So the error can only be caused by shared_ptr being actually undefined.
Now libc++ obviously has a definition shared_ptr, so I can only suspect some C++03 library made it to the include path somehow and got preferred over libc++.

How can I have g++ mimic MSVC++'s template instantiation behavior?

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.

g++ C++0x enum class Compiler Warnings

I've been refactoring my horrible mess of C++ type-safe psuedo-enums to the new C++0x type-safe enums because they're way more readable. Anyway, I use them in exported classes, so I explicitly mark them to be exported:
enum class __attribute__((visibility("default"))) MyEnum : unsigned int
{
One = 1,
Two = 2
};
Compiling this with g++ yields the following warning:
type attributes ignored after type is already defined
This seems very strange, since, as far as I know, that warning is meant to prevent actual mistakes like:
class __attribute__((visibility("default"))) MyClass { };
class __attribute__((visibility("hidden"))) MyClass;
Of course, I'm clearly not doing that, since I have only marked the visibility attributes at the definition of the enum class and I'm not re-defining or declaring it anywhere else (I can duplicate this error with a single file).
Ultimately, I can't make this bit of code actually cause a problem, save for the fact that, if I change a value and re-compile the consumer without re-compiling the shared library, the consumer passes the new values and the shared library has no idea what to do with them (although I wouldn't expect that to work in the first place).
Am I being way too pedantic? Can this be safely ignored? I suspect so, but at the same time, having this error prevents me from compiling with Werror, which makes me uncomfortable. I would really like to see this problem go away.
You can pass the -Wno-attributes flag to turn the warning off.
(It's probably a bug in gcc?)
It works for me with g++ 4.8.2 the following way:
enum class MyEnum : unsigned int
__attribute__((visibility("default")))
{
One = 1,
Two = 2
};
(change the position of the attribute declaration)

Visibility of template specialization of C++ function

Suppose I have fileA.h which declares a class classA with template function SomeFunc<T>(). This function is implemented directly in the header file (as is usual for template functions). Now I add a specialized implementation of SomeFunc() (like for SomeFunc<int>()) in fileA.C (ie. not in the header file).
If I now call SomeFunc<int>() from some other code (maybe also from another library), would it call the generic version, or the specialization?
I have this problem right now, where the class and function live in a library which is used by two applications. And one application correctly uses the specialization, while another app uses the generic form (which causes runtime problems later on). Why the difference? Could this be related to linker options etc? This is on Linux, with g++ 4.1.2.
It is an error to have a specialization for a template which is not visible at the point of call. Unfortunately, compilers are not required to diagnose this error, and can then do what they like with your code (in standardese it is "ill formed, no diagnostic required").
Technically, you need to define the specialization in the header file, but just about every compiler will handle this as you might expect: this is fixed in C++11 with the new "extern template" facility:
extern template<> SomeFunc<int>();
This explicitly declares that the particular specialization is defined elsewhere. Many compilers support this already, some with and some without the extern.
Have you added a prototype with parameters to your header file?
I mean is there somewhere in fileA.h
template<> SomeFunc<int>();
If not that's probably the reason.
I had the same problem with gcc4, here is how i solved it. It was more simple a solution than what i was lead to believe by previous comments. The previous posts ideas were correct but their syntax didn't work for me.
----------header-----------------
template < class A >
void foobar(A& object)
{
std::cout << object;
}
template <>
void foobar(int);
---------source------------------
#include "header.hpp"
template <>
void foobar(int x)
{
std::cout << "an int";
}
Per the specs, your specialized function template should never be called outside fileA.C, unless you export the template definition, which no compiler (except Comeau) currently supports (or has it planned for the forseeable future).
On the other hand, once the function template is instantiated, there is a function visible to the compiler that is no longer a template. GCC may re-use this definition across different compiler units because the standard states that each template shall only be instantiated once for a given set of type arguments [temp.spec]. Still, since the template is not exported, this should be limited to the compilation unit.
I believe that GCC may expose a bug here in sharing its list of instantiated templates across compilation units. Normally, this is a reasonable optimization but it should take function specializations into account which it doesn't seem to do correctly.
In Microsoft C++, I did an experiment with inline functions. I wanted to know what would happen if I defined incompatible versions of a function in different sources. I got different results depending on whether I was using a Debug build or a Release build. In Debug, the compiler refuses to inline anything, and the linker was linking the same version of the function no matter what was in scope in the source. In Release, the compiler inlined whichever version had been defined at the time, and you got differing versions of the function.
In neither case were there any warnings. I kind of suspected this, which is why I did the experiment.
I assume that template functions would behave the same, as would other compilers.
As Anthony Williams says, the extern template construct is the correct way to do this, but since his sample code is incomplete and has multiple syntax errors, here's a complete solution.
fileA.h:
namespace myNamespace {
class classA {
public:
template <class T> void SomeFunc() { ... }
};
// The following line declares the specialization SomeFunc<int>().
template <> void classA::SomeFunc<int>();
// The following line externalizes the instantiation of the previously
// declared specialization SomeFunc<int>(). If the preceding line is omitted,
// the following line PREVENTS the specialization of SomeFunc<int>();
// SomeFunc<int>() will not be usable unless it is manually instantiated
// separately). When the preceding line is included, all the compilers I
// tested this on, including gcc, behave exactly the same (throwing a link
// error if the specialization of SomeFunc<int>() is not instantiated
// separately), regardless of whether or not the following line is included;
// however, my understanding is that nothing in the standard requires that
// behavior if the following line is NOT included.
extern template void classA::SomeFunc<int>();
}
fileA.C:
#include "fileA.h"
template <> void myNamespace::classA::SomeFunc<int>() { ... }
Brandon: that's what I thought - the specialized function should never be called. Which is true for the second application I mentioned. The first app, however, clearly calls the specialized form even though the specialization is not declared in the header file!
I mainly seek enlightenment here :-) because the first app is a unit test, and it's unfortunate to have a bug that doesn't appear in the test but in the real app...
(PS: I have fixed this specific bug, indeed by declaring the specialization in the header; but what other similar bugs might still be hidden?)
#[anthony-williams],
are you sure you're not confusing extern template declarations with extern template instantiations? From what I see, extern template may only be used for explicit instantiation, not for specialization (which implies implicit instantiation). [temp.expl.spec] doesn't mention the extern keyword:
explicit-specialization:
template < > declaration
Unless the specialized template function is also listed in the header file, the other application will have no knowledge of the specialized version. The solution is the add SomeFunc<int>() to the header as well.