2012-06-14 1 views
8

В следующем коде вариационный конструктор вызывается дважды. Как я могу получить вызов конструктора копии вместо единственной версии аргумента вариационного конструктора, когда это необходимо?Как получить конструктор копирования, вызванный над конструктором Variadic?

#include <iostream> 

struct Foo 
{ 
    Foo(const Foo &) 
    { 
     std::cout << "copy constructor\n"; 
    } 

    template<typename... Args> 
    Foo(Args&&... args) 
    { 
     std::cout << "variadic constructor\n"; 
    } 

    std::string message; 
}; 

int main() 
{ 
    Foo f1; 
    Foo f2(f1); // this calls the variadic constructor, but I want the copy constructor. 
} 

ответ

9

В этом на самом деле не имеет ничего общего с тем, что конструктор является VARIADIC. Следующий класс с шаблоном, не VARIADIC конструктор имеет такое же поведение:

struct Foo 
{ 
    Foo() { } 

    Foo(const Foo& x) 
    { 
     std::cout << "copy constructor\n"; 
    } 

    template <typename T> 
    Foo(T&& x) 
    { 
     std::cout << "template constructor\n"; 
    } 

}; 

Проблема заключается в том, что шаблон конструктор лучше подходит. Чтобы вызвать конструктор копирования, требуется конверсия квалификации для привязки неконстантного lvalue f1 к const Foo& (должна быть добавлена ​​квалификация константы).

Для вызова шаблона конструктора, не требуется никаких преобразований: T может быть выведено Foo&, который после ссылки разрушающейся (Foo& && ->Foo&), дает параметр x тип Foo&.

Вы можете обойти это, предоставив второй конструктор копий, который имеет опорный параметр non-const lvalue Foo&.

+1

Существует немного больше, а именно ссылка сбрасывается (как это называется?), Т. Е. 'T &&&' => 'T &, потому что иначе lvalue (' f1') не может связываться с 'T &&'. –

4

Просто обеспечить перегрузку с точным соответствием, то есть один с не- constFoo&, в дополнение к обычному конструктору копирования. Затем вы можете передать вызов посредством явного приведения:

Foo(Foo& other) : Foo(static_cast<Foo const&>(other)) { }