- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I've just run into a linker error which can be tracked down to the following minimal code
#include <iostream>
#include <vector>template <size_t A, size_t B>
class some_class
{private:
std::vector<size_t> vec;public:
static constexpr size_t product = A * B;
some_class() :
vec ()
// vec (1, product) /* Undefined reference */
{
// vec.push_back(product); /* Undefined reference */
vec[0] = product; /* But this is fine!*/
};
size_t get(size_t loc) { return vec[loc]; }};
int main()
{
some_class<2,3> some_object;
std::cout << some_object.get(0) << std::endl;
return 0;
}
The above code compiles and links correctly under the latest release of icpc with -std=c++11.
The two commented-out lines obviously represent two other ways of achieving the same result, however swapping out "vec[0] = product" with either of the alternatives causes the linker to complain about missing reference to some_class::product.
Strangely enough, if one were to include BOTH the initialisation list AND the vec[0] assignment then the linker stops complaining again.
Could I get some confirmation if this is a compiler bug or if I'm doing something which violates the C++11 standard?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I should quickly add also that g++-4.7.1 with -std=c++11 (which is the latest version I have handy) does not complain in any of the cases shown above.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Isn't your class declaration wrong? You have a static member variable, one instance per class (not instance of each instance of class), who's value may vary dependent on the values of A, B in the construction. You may need to remove "static" from product. Consider:
some_class<2,3> some_object;
some_class<4,5> other_object;
what do you expect for the one instance of some_class::product?
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Not really. Since A and B are template parameters, some_class::product isn't even defined. You would actually have to call some_class<A,B>::product where A and B are compile-time constants.
Indeed, in the example code above the linker complains
Undefined symbols for architecture x86_64:
"__ZN10some_classILm2ELm3EE7productE", referenced from:
_main in test.o
where __ZN10some_classILm2ELm3EE7productE demangles to some_class<2ul, 3ul>::product as expected.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Agreed, in this case an instance of some_class<2,3> has been created. However, as defined the product member should have been fixed to 2*3 at compile time when the compiler instantiates the template (that is the point of static constexpr after all -- I am actually using this as part of a larger template metaprogram), not when the object is created.
To make this clearer, I could've simplified the code as follows
#include <iostream>
template <size_t A, size_t B>
class some_class
{
public:
static constexpr size_t product = A * B;
};
int main()
{
std::cout << some_class<2,3>::product << std::endl;
return 0;
}
Indeed, the above code would compile, link, and run correctly. Likewise, if I now change main() to
int main()
{
std::vector<size_t> vec(1, some_class<2,3>::product);
std::cout << vec[0] << std::endl;
return 0;
}
Then once again the icpc linker complains, but g++ does not. Note that this time round I have not instantiated any object of type some_class<A,B> at all.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>>where __ZN10some_classILm2ELm3EE7productE demangles to some_class<2ul, 3ul>::product as expected
I was under the (false) impression that some_calss<size_t,size_t>::product would be generated.
Does the failure occur in Debug build? (iow, is optimization involved)
If not (optimization is involved), then try adding an unused member function that uses product.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It is done in a declaration of the vector:
...
std::vector vec( 1, some_class< 2, 3 >::product );
...
Only the static value product is referred to here, no actual object is instantiate.
Does the failure occur in Debug build? (iow, is optimization involved)
Failure still occurs with -O0 -g. I've been searching on SO about this and there's some confusion about the declaration, definition and initialization of constexpr static members. I am under the impression that the initialization value needs to be specified at the point of declaration (which is what happens in the code above), however some people also says this does not constitute a definition of said member (which I find a bit puzzling).
Inspired by the above logic, I tried adding
template <size_t A, size_t B> constexpr size_t some_class<A,B>::product;
outside the class definition. This forces icc to generate the external symbol which can be linked against. Note that gcc actually just evaluates product = 6 uses this in the generated binary code without any reference to the ::product symbol, which is what the behaviour I expected.
I guess the real question is: is gcc or the icc behaviour the non-standard one here.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The object is not added to the vector, only the size_t value of 6. (i.e. in all the versions of the above code I should be getting vec[0] = 6.)
Note that vec is a std::vector<size_t>, not std::vector<some_class>.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the verification. I'm getting the error on icpc 13.0.2 20130314 on Mac OS X 10.8. This is the latest version I have access to on Intel's download page.
My question is why do you need additional member product?
This is actually part of a template metaprogram involving the new C++11 variadic templates. The 'real' code defines something like
template <size_t N...>
class some_class;
along with an auxiliary class with compile-time logic to compute the product from a list of size_t constants. I'm afraid there really isn't an alternative here other than defining a static constexpr.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Compiling with -std=c++0x doesn't change anything.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There used to be an old compiler issue relating to private and public. Try placing:
public:
static constexpr size_t product = A * B;
At the front of the class declaration (iow, in front of the private:)
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I've tried this and it works with latest 13.1 icl (x64) on SUSE with gcc 4.5:
#include <iostream>
#include <vector>
template <size_t A, size_t B>
class some_class {
public:
static constexpr size_t product = A * B;
};
int main() {
std::vector<size_t> vec(1, some_class<2,3>::product);
std::cout << vec[0] << std::endl;
return 0;
}
$icpc -std=c++11 tt.cpp
Jennifer
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Also tried the code on the original post, it can be built fine as well on the same Suse Linux with gcc 4.5.
Jennifer

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page