다음 프로그램을 고려하십시오.
#include <string>
#include <vector>
using namespace std;
struct T
{
int a;
double b;
string c;
};
vector<T> V;
int main()
{
V.emplace_back(42, 3.14, "foo");
}
작동하지 않습니다.
$ g++ -std=gnu++11 ./test.cpp
In file included from /usr/include/c++/4.7/x86_64-linux-gnu/bits/c++allocator.h:34:0,
from /usr/include/c++/4.7/bits/allocator.h:48,
from /usr/include/c++/4.7/string:43,
from ./test.cpp:1:
/usr/include/c++/4.7/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = T; _Args = {int, double, const char (&)[4]}; _Tp = T]’:
/usr/include/c++/4.7/bits/alloc_traits.h:253:4: required from ‘static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = T; _Args = {int, double, const char (&)[4]}; _Alloc = std::allocator<T>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]’
/usr/include/c++/4.7/bits/alloc_traits.h:390:4: required from ‘static void std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = T; _Args = {int, double, const char (&)[4]}; _Alloc = std::allocator<T>]’
/usr/include/c++/4.7/bits/vector.tcc:97:6: required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int, double, const char (&)[4]}; _Tp = T; _Alloc = std::allocator<T>]’
./test.cpp:17:32: required from here
/usr/include/c++/4.7/ext/new_allocator.h:110:4: error: no matching function for call to ‘T::T(int, double, const char [4])’
/usr/include/c++/4.7/ext/new_allocator.h:110:4: note: candidates are:
./test.cpp:6:8: note: T::T()
./test.cpp:6:8: note: candidate expects 0 arguments, 3 provided
./test.cpp:6:8: note: T::T(const T&)
./test.cpp:6:8: note: candidate expects 1 argument, 3 provided
./test.cpp:6:8: note: T::T(T&&)
./test.cpp:6:8: note: candidate expects 1 argument, 3 provided
이를 수행하는 올바른 방법은 무엇이며 그 이유는 무엇입니까?
(또한 단일 및 이중 중괄호 시도)
답변
답변
클래스에 대한 ctor를 명시 적으로 정의해야합니다.
#include <string>
#include <vector>
using namespace std;
struct T
{
int a;
double b;
string c;
T(int a, double b, string &&c)
: a(a)
, b(b)
, c(std::move(c))
{}
};
vector<T> V;
int main()
{
V.emplace_back(42, 3.14, "foo");
}
사용의 요점은 emplace_back
임시 객체를 생성하지 않고 대상으로 복사 (또는 이동)하는 것입니다. 임시 객체를 만든 다음에 전달하는 것도 가능하지만 emplace_back
(적어도 대부분의) 목적을 무효화합니다. 원하는 것은 개별 인수를 전달한 다음 emplace_back
해당 인수로 ctor를 호출하여 제자리에 객체를 생성하는 것입니다.
답변
물론 이것은 대답이 아니지만 튜플의 흥미로운 기능을 보여줍니다.
#include <string>
#include <tuple>
#include <vector>
using namespace std;
using T = tuple <
int,
double,
string
>;
vector<T> V;
int main()
{
V.emplace_back(42, 3.14, "foo");
}
답변
생성자를 추가하고 싶지 않거나 추가 할 수없는 경우 T에 대한 할당자를 전문화하거나 고유 한 할당자를 만듭니다.
namespace std {
template<>
struct allocator<T> {
typedef T value_type;
value_type* allocate(size_t n) { return static_cast<value_type*>(::operator new(sizeof(value_type) * n)); }
void deallocate(value_type* p, size_t n) { return ::operator delete(static_cast<void*>(p)); }
template<class U, class... Args>
void construct(U* p, Args&&... args) { ::new(static_cast<void*>(p)) U{ std::forward<Args>(args)... }; }
};
}
참고 : 위에 표시된 멤버 함수 구성은 clang 3.1로 컴파일 할 수 없습니다 (죄송합니다. 이유를 모르겠습니다). clang 3.1 (또는 다른 이유)을 사용하려면 다음을 시도하십시오.
void construct(T* p, int a, double b, const string& c) { ::new(static_cast<void*>(p)) T{ a, b, c }; }
답변
이것은 23.2.1 / 13에서 다루는 것 같습니다.
첫째, 정의 :
A와 동일한 allocator_type 및 T와 동일한 value_type을 가지며 A 유형의 lvalue m, 유형 T *의 포인터 p, 유형 T의 표현식 v 및 유형 T의 rvalue rv를 갖는 컨테이너 유형 X가 주어지면, 다음 용어가 정의됩니다.
이제 emplace-constructible로 만드는 것은 무엇입니까?
T는 args에서 X로 EmplaceConstructible입니다. 인수가 0 개 이상인 경우 args는 다음 표현식이 잘 구성되었음을 의미합니다. allocator_traits :: construct (m, p, args);
마지막으로 구성 호출의 기본 구현에 대한 참고 사항 :
참고 : 컨테이너는 allocator_traits :: construct (m, p, args)를 호출하여 args를 사용하여 p에서 요소를 생성합니다. std :: allocator의 기본 구조는 :: new ((void *) p) T (args)를 호출하지만 특수 할당자는 다른 정의를 선택할 수 있습니다.
이것은 기본 (그리고 잠재적으로 유일한) 할당 자 체계의 경우 컨테이너에 배치하려는 항목에 대해 적절한 수의 인수를 사용하여 생성자를 정의 해야 함 을 거의 알려줍니다 .
답변
사소하지 않은를 T
포함하고 있기 때문에 유형에 대한 생성자를 정의해야합니다 std::string
.
더욱이, 이동 ctor / 할당을 정의하는 것이 더 좋을 것입니다 (기본적으로 가능) 이동 ctor / 할당 ( std::string
멤버로서 이동식이 있기 때문에 )-이것은 T
훨씬 더 효율적 으로 이동하는 데 도움이 될 것입니다 .
또는 neighboug 응답에서 권장하는대로 T{...}
오버로드 emplace_back()
된 호출에 사용 합니다 … 모든 것은 일반적인 사용 사례에 따라 다릅니다 …
답변
struct T
인스턴스를 만든 다음 벡터로 이동할 수 있습니다 .
V.push_back(std::move(T {42, 3.14, "foo"}));