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++.
Related
Today, I encountered a compile issue in clang that surprised me. I guess is reasonable but I like to dig deeper and hear more details. Some standard references if possible also.
I have a class with a template method which rely on a member which his type is undefined in the header (but not in the source). Something like the following:
// Menu.h
class Page;
class Menu
{
public:
.... // stuff
template<class Visitor>
void VisitWidget( Visitor&& visitor);
private:
std::unique_ptr<Page> m_page; // destructor implemented in source file, so Page is an incomplete type
};
template<class Visitor>
inline void Menu::VisitWidget( Visitor&& visitor);
{
m_page->Visit( std::forward<Visitor>(visitor) );
}
In VisualStudio, it compiles. I expect this to only complain when instanciating; so inlining. However, in clang, this doesn't compile as soon as someone includes the header. Forcing me to include Page.h in Menu.h (which I want to avoid at all cost).
Like:
// Another.cpp (not Menu.cpp)
#include "Menu.h" // this trigger and error due Page is an incomplete type
even if the whole Another.cpp is not using VisitWidget (even in other headers)
I guess that this is caused by inline somehow, since the compiler is not obligated to really use it, but since there are templates in the middle I am not so sure. Is really clang checking the type?
Yes, this compiles in MSVC because it has a well-known bug. It doesn't implement two-step template instantiation.
To elaborate. MSVC wrongly defers template parsing until it is actually instantiated in the code. Likely it happens after full Page definition becomes visible.
However, standard demands that the template is pre-parsed at the point of definition, and all types which are not dependent on template arguments are resolved. This fails, since m_page is not dependent on visitor argument - and it is still incomplete type at this point.
P.S. I can't even express how outraged I am at MSFT for this blatant Standard violation (among others). It makes cross-platform development a real pain, when MS-compliant code has to be ported to conforming compilers.
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 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.
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.