This code produces a warning: "declaration requires a global constructor [-Wglobal-constructors]"
// Compile with -Wglobal-constructors
class T {
public:
constexpr T(int* p) : ptr_(p) {}
T(const T& other) : T(other.ptr_) {}
private:
int* ptr_;
};
struct MyStruct {
int x;
T y;
};
MyStruct s[] {{ 123, nullptr },{ 234, nullptr }};
I thought adding constexpr T(std::nullptr_t) : ptr_(nullptr) {} would take care of it, but no. Instead, making the copy constructor constexpr does, which puzzles me. Same applies to a move constructor, if there was one.
Turns out that this behavior continues until C++14, but is no longer the case in C++17, where copy elision covers this case.
Related
I have a C++11 template that can be specialized with an arbitrary type parameter.
template<class ElementType>
class Foo
How do I declare a constructor that appears for the compiler's consideration only when ElementType is e.g. const uint8_t?
That is, I have a bunch of constructors that are generic over any ElementType, but I also want to have constructors that are only considered when ElementType is specialized in a particular way. (Allowing those constructors to be selected for other types would be unsafe.)
So far std::enable_if examples that I've found have been conditional on the types of the arguments of the constructors.
template<class ElementType>
struct Foo
{
template <typename T = ElementType>
Foo(typename std::enable_if<!std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
template <typename T = ElementType>
Foo(typename std::enable_if<std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
};
int main()
{
Foo<int> a{}; // ok, calls first constructor
Foo<const uint8_t> b{}; // ok, calls second constructor
}
wandbox example
You can break the class into two classes. The derived class' purpose is to be able to specialize constructors for different types. E.g.:
#include <cstdio>
#include <cstdint>
template<class ElementType>
struct Foo_
{
Foo_() { std::printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class ElementType>
struct Foo : Foo_<ElementType>
{
using Foo_<ElementType>::Foo_; // Generic version.
};
template<>
struct Foo<uint8_t> : Foo_<uint8_t>
{
Foo() { std::printf("%s\n", __PRETTY_FUNCTION__); } // Specialization for uint8_t.
};
int main(int ac, char**) {
Foo<int8_t> a;
Foo<uint8_t> b;
}
The benefit of using the derived class here compared to enable_if is that:
The class can be partially specialized.
Only one specialization of the class is chosen for particular template parameters, rather than a set of constructors. When adding specializations for new types the existing enable_if expressions may need to be changed to make them more restrictive to avoid function overload set resolution ambiguity.
I was wondering about this. Consider this:
#include <iostream>
#include <map>
#include <memory>
int main() {
std::map< int, std::unique_ptr<int> > m =
{ { 1, std::unique_ptr<int>(new int(3)) } };
return(0);
}
This is C++11. It fails to compile with a long ream of error messages on GCC, including one
/usr/include/c++/4.9/ext/new_allocator.h:120:4: error: use of deleted function ‘constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
Is it possible at all to do what I'm trying to do here? I note that with shared_ptr, it works OK. Is it possible to do it with unique_ptr? If so, what am I missing? If not, why not?
No.
The elements of an initializer_list cannot be modified.
The unique_ptr cannot be moved (because it's const) and it can't be copied (because it's a move-only type), so you're hosed.
Sure, no problem.
First, a smart unique_ptr proxy, so we can create and move them around in a const context:
template<class T>
struct il_up {
mutable std::unique_ptr<T> ptr;
template<class U,
std::enable_if_t< std::is_convertible<U*, T*>{}, int>* =nullptr
>
il_up( std::unique_ptr<U> o ): ptr(std::move(o)) {}
operator std::unique_ptr<T>() const {
return std::move(ptr);
}
};
We then want to store this in an initializer_list. Even though it is const, it can pass the unique_ptr out.
Then a container-making proxy to store the temporary initializer list:
template<class T>
struct make_container {
std::initializer_list<T> il;
make_container( std::initializer_list<T> const& l ):il(l) {} // const& here matters
template<class C>
operator C()&&{
return {il.begin(), il.end()};
}
};
and we are done:
std::vector<std::unique_ptr<int>> vec = make_container<il_up<int>>{
std::make_unique<int>(1), std::make_unique<int>(2),
std::make_unique<int>(3), std::make_unique<int>(4)
};
live example.
the following code produces an internal compiler error (VS2015)
struct A
{
constexpr A(){}
constexpr int bar()
{
return 3;
}
};
struct B : A
{
constexpr B(){}
constexpr int foo()
{
return A::bar();
}
};
int main()
{
constexpr B b;
constexpr int dummy = b.foo();
return 1;
}
However, if i'd remove the A:: qualifier:
constexpr int foo()
{
return bar();
}
it will be compiled.
problem arises when these methods have the same name, and I need to invoke the base class method. (e.g. when using recursive template inheritence)
any workarounds?
The actual problem is b is declared as const (constexpr implies const on objects) and you are trying to call non-const (since C++14, constexpr doesn't imply const on methods, see here) method with the const object...
According to the standard, you should not be able to solve the problem by simply removing A:: nor by the static_cast the way you did. Pre-RTM version of Visual Studio 2015 allows you to do this only because its support for constexpr is preliminary and very buggy. C++11 constexpr (but unfortunately not C++14 extended constexpr) expected to be fully supported in the RTM version of VS 2015 (see here).
The correct version of your code is:
struct A
{
constexpr A(){}
constexpr int bar() const
{
return 3;
}
};
struct B : A
{
constexpr B(){}
constexpr int foo() const
{
return A::bar();
}
};
int main()
{
constexpr B b;
constexpr int dummy = b.foo();
return 1;
}
Found a solution.
"this" should be casted to const A*:
struct B : A
{
constexpr B(){}
constexpr int foo()
{
return static_cast<const A*>(this)->bar();
}
};
Also works when the methods have the same name.
Follwing short programm will run perfect with VS 2013 and reach the marked point. But in XCode the compiler will show an error due ambiguous constructor. How to work around?
#include <iostream>
#include <string>
class atest
{
public:
explicit operator const char *()
{
return "";
}
template<class T> operator T()
{
}
operator std::string()
{
return std::string("Huhuhu");
}
template<class T> atest &operator =(T value)
{
}
atest &operator =(const std::string &value)
{
return *this; // I want to reach this point
}
};
int main(int argc, char* argv[])
{
atest tst;
// auto a = (std::string)tst;
std::string astr;
// do some stuff
astr=tst; // I wanna keep this line
return 0;
}
Clang is not able to distinguish between different constructor where VS2013 is taking the right one. I search now for a way to exclude the "const char *" template of the assignment operator.
std::string have multiple constructors taking single arguments, and since you provide both a conversion operator for std::string and a generic any-type conversion operator, the compiler simply don't know which constructor to pick.
I think you have written far too many overloaded functions. The only function you need is this:
operator std::string()
{
return std::string("Huhuhu");
}
Comment rest all and your code would work just fine.
In MSVC 2008, I have the following code:
class Foo {
// Be a little smarter about deriving the vertex type, to save the user some typing.
template<typename Vertex> inline void drawVertices(
Elements vCount, RenPrim primitiveType, PixMaterial *mtl, Vertex const *vertices)
{
this->drawVertices(vCount, primitiveType, mtl, vertices, Vertex::VertexType);
}
virtual void drawVertices(
Elements vCount,
RenPrim primitiveType,
PixMaterial *mtl,
void const *vertices,
uint vertexType) = 0;
};
I use it something like:
struct RenFlexibleVertexPc
{
enum { VertexType = RenVbufVertexComponentsPc };
float x;
float y;
float z;
GraVideoRgba8 c; // Video format, not external!
};
PixMaterial *material;
struct Pc : RenFlexibleVertexPc
{
void set(Triple t, uint cl) { x = (float)t.x_; y = (float)t.y_; z = (float)t.z_; c = cl; }
} vpc[4];
...
Foo *renderer;
renderer->drawVertices(4, RenPrimTriangleFan, material, vpc);
This works fine in MSVC 2008 SP1. However, GCC (3.4 and 4.1,2) throws a "no matching function for call to function" error, apparently not seeing the template when there is a non-template function with more arguments.
Is GCC broken, or is my code broken, and if so, why?
There is no problem with overloading or inheritance:
#include <iostream>
#include <memory>
namespace {
struct A {
virtual void f()
{
std::cout<<"inside A's f()\n";
}
template <typename T> void f(T t)
{
std::cout<<T::i<<'\t';
this->f();
}
};
struct B : A {
void f()
{
std::cout<<"hello\t";
A::f();
}
};
struct C {
static const unsigned int i = 5;
};
struct D {
enum { i = 6 };
};
}
int main()
{
std::auto_ptr<A> b(new B());
b->f(C());
b->f(D());
}
Works correctly. On the other hand, the smallest example I can find that exhibits your problem does not have inheritance or overloading:
#include <iostream>
namespace {
struct A {
template<class C> void print(C c)
{
c.print();
}
};
}
int main()
{
struct B {
void print()
{
std::cout << "whee!\n";
}
};
A a;
B b;
a.print(b);
}
Note that if struct B is defined in a namespace (whether it's an unnamed namespace, or a completely different namespace, or the global namespace) instead of inside main() that this compiles without error.
I don't know enough of the standard to say if this is a bug, but it appears to be one. I've gone ahead and reported it to the GCC bug database.
And here's your answer from the GCC developers (from the link above): "Local classes cannot be template arguments."
So the code is broken. Not that it's a bad idea. In fact, C++0x removes this restriction.
I noticed the line
Note that the code works in GCC if I explicitly cast vpc to (RenFlexibleVertexPc *)
And since RenFlexibleVertexPc is not a local class this makes sense. However Pc is a local class/struct, so it is not allowed.
#OP: Specifying the template parameter is a valid approach.
renderer->drawVertices<RenFlexibleVertexPc>(4, RenPrimTriangleFan, material, vpc);
With Pete's additions, you code also compiles on Apple's GCC 4.0.1, so I suspect there's something your posted code is missing that's causing the problem.
#Max: GCC's treatment of your source is standard. Struct B is local to main(), so B (and thus main()::B::print()) is not visible outside main(). As you're probably aware, moving the definition of B outside of main() and it will compile.
The definition of VertexType is already in the code (an enum). Elements is an unsigned long. Note that the code works in GCC if I explicitly cast vpc to (RenFlexibleVertexPc *)
If it's an enum why pass an object of type array 4 of struct? What is RenFlexibleVertexPc? The last argument to drawVertices should either be a constant pointer to a Vertex object or a const* to an object of a class derived from Vertex.
Foo *renderer;
renderer->drawVertices(4, RenPrimTriangleFan, material, vpc);
You are calling a function on an uninitialized pointer. I hope this is not the real code. \