2017-10-03 24 views
6

xem xét mã này:Tôi có thể tránh viết một cách rõ ràng một hàm tạo cho mỗi cấu trúc trong một biến thể :: std không?

#include <variant> 

struct x { 
    int y; 
}; 

int main() { 
    std::variant<x> v(std::in_place_type<x>, {3}); /*1*/ 
    return std::get<x>(v).y; 
} 

này không biên dịch và cũng như thế khi tháo {} từ dòng /*1*/, mặc dù tổng khởi

x a{3}; 
x b({3}); 

công trình trong cả hai hình thức "nhà xây dựng giống như". Bằng cách nào đó tôi có thể làm cho bộ khởi tạo std::variant nhận biết khả năng xây dựng các cấu trúc bằng cách khởi tạo tổng hợp mà không cần phải viết các nhà xây dựng boilerplate nhàm chán cho mỗi cấu trúc có thể được sử dụng trong trường hợp thế giới thực của tôi không?

tôi sẽ mong đợi điều này để làm việc, bằng cách nào đó, theo cppreference hai định nghĩa chồng (5) và (6) trong câu hỏi đều nói

Constructs một biến thể với phương án quy định T và khởi giá trị chứa với các đối số [...]

Tôi đang sử dụng GCC 7 nếu vấn đề đó quan trọng.

+0

Nếu nó điều khiển bạn, 'std :: make_unique' và gia đình có cùng giới hạn: ( – Rakete1111

+0

khởi tạo tổng hợp luôn là dấu hiệu trong hệ thống khởi tạo C++ –

Trả lời

1

Không có cách giải quyết nào cho việc này ngoài việc thêm hàm tạo. Các nhiệm vụ tiêu chuẩn này cho cả quá tải bạn đề cập đến, [variant.ctor]19[variant.ctor]23 tương ứng:

Hiệu ứng: Khởi tạo giá trị chứa như thể trực tiếp phi-list-khởi tạo một đối tượng kiểu T với các đối số std​::​forward<Args>(args)....

Hiệu ứng: Khởi tạo giá trị chứa như thể trực tiếp không liệt kê-khởi tạo đối tượng thuộc loại T với đối số il, std​::​forward<Args>(args)....

Bạn luôn có thể sao chép hoặc di chuyển các đối tượng sử dụng:

std::variant<x> v(std::in_place_type<x>, x{3}); 
// or more clear and does the same thing 
std::variant<x> v(x{3}); 
3

Có lẽ nó không chính xác những gì bạn đang hỏi, nhưng những gì về xây dựng một cách rõ ràng đối tượng thay vì dựa vào suy luận kiểu?

#include <variant> 

struct x { 
    int y; 
}; 

int main() { 
    std::variant<x> v(std::in_place_type<x>, x{3}); 
    return std::get<x>(v).y; 
} 
+0

Thực ra tôi sẽ hài lòng với điều này!Câu hỏi của tôi, mỗi tiêu đề, là về tránh các nhà xây dựng, mà điều này đạt được. Nó sẽ về mặt kỹ thuật liên quan đến một số di chuyển xung quanh, nhưng trong trường hợp đơn giản, trình tối ưu hóa sẽ chăm sóc mà không có phí. –

+0

Thực tế nó sẽ rất đơn giản nếu lớp của bạn cung cấp một hàm tạo chuyển động. Vì bạn không muốn bất kỳ constructor được định nghĩa rõ ràng nào, bạn nên đảm bảo hàm khởi tạo ngầm (hoặc ít nhất là defaulting). – cbuchart

0

Nếu bạn muốn đi quá mức cần thiết, chúng ta có thể tạo ra một loại máy mà có một nhà điều hành chuyển đổi:

template <class... Args> 
struct list_init_from { 
    std::tuple<Args...> args; 

    template <class T> 
    operator T() { 
     return std::apply([](auto... args){ 
      return T{args...}; 
     }, args); 
    } 
}; 

template <class... Args> 
list_init_from(Args...) -> list_init_from<Args...>; 

nào bạn có thể sử dụng:

std::variant<x> v(std::in_place_type<x>, list_init_from{3}); 

Công trình này, nhưng để lại mu ch được mong muốn: chuyển tiếp hoàn hảo, SFINAE trên toán tử chuyển đổi và chỉ định rõ loại nào cho phép chuyển đổi là các bài tập được để lại cho người đọc.

Các vấn đề liên quan