Re: move/copy constructors, variadic constructors, and private inheritance, is this a compiler bug?
On 2013-07-12 10:11, fmatthew5876 wrote:
I'm designing an allocator interface and came across a strange bug in
C++11
Your code was (reformatted and removing the explicit template parameters
when they refer to the same class):
#include <utility>
class DefaultAllocatorImpl {};
template <typename A>
class Allocator : public A {
public:
Allocator(const Allocator& b) : A(b) {}
Allocator(Allocator&& b) : A(std::move(b)) {}
template <typename... Args>
Allocator(Args&&... args) : A(std::forward<Args>(args)...) {}
};
typedef Allocator<DefaultAllocatorImpl> DefaultAllocator;
template <typename T, typename ALLOC = DefaultAllocator>
class Container : private ALLOC {
public:
Container();
Container(const Container& c) : ALLOC(c) {}
Container(Container&& c) : ALLOC(std::move(c)) {}
};
template class Container<int>;
int main() {
Container<int> ct;
return 0;
}
This code fails to compile on both gcc 4.7.1 and clang 3.2.
If I comment out the
template <typename... Args>
Allocator(Args&&... args) : A(std::forward<Args>(args)...) {}
constructor it compiles just fine.
Shouldn't the compiler choose Allocator(const Allocator&) and
Allocator(Allocator&&) over the more generic variadic one?
No, because the actual argument type is Container<int> and is not
identical to DefaultAllocator. The "perfect-forwarding" constructor
template considers the instantiation of
DefaultAllocator::DefaultAllocator(Container<int>&&);
and
DefaultAllocator::DefaultAllocator(const Container<int>&);
as a better match because it fits "perfectly" and doesn't require a
conversion to a base class.
Is this the correct behavior or a compiler bug?
I think this is correct behaviour.
If this behavior is correct, how can I forward the move/copy
constructors correctly while still retaining the variadic one?
Just ensure that you forward the correct ALLOC subobject to the ALLOC
constructor:
Container(const Container& c) : ALLOC(static_cast<const ALLOC&>(c)) {}
Container(Container&& c) : ALLOC(static_cast<ALLOC&&>(std::move(c))) {}
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]