2016-06-10 23 views
6

Ví dụCách triển khai khởi tạo thuận tiện?

#include <array> 

class Range 
{ 
public: 
    Range(std::array<float, 2> ends) : m_ends(ends) {} 

private: 
    std::array<float, 2> m_ends;  
}; 

và tôi có thể

Range r({1, 2}); 

Bây giờ tôi có một lớp

class Box 
{ 
public: 
    Box(std::array<Range, 3> ranges) : m_ranges(ranges) {} 

private: 
    std::array<Range, 3> m_ranges;  
}; 

Và tôi hy vọng tôi có thể làm như sau

Box b({{1,2}, {3,4}, {5,6}}); 

Nhưng tôi không thể. Làm thế nào tôi có thể thay đổi mã để làm cho nó có thể.

+2

này hoạt động: 'Box b {{{{{1, 2}}, {{3,4}}, {{5,6}}}}} '. – user1887915

Trả lời

4

std::array là một chút lạ. Nó không có một hàm tạo do người dùng định nghĩa, vì vậy nó rất giống một cấu trúc đơn giản. Vì vậy std::array<float,2> là giống như

struct two_floats { 
    float array[2]; 
}; 

Bởi vì điều này, nếu bạn khởi tạo một, bạn sẽ logic làm điều đó như thế này:

two_floats   x = {{1,2}}; 
std::array<float,2> y = {{1,2}}; 

Các niềng răng bên ngoài là dành cho các struct chính nó, và niềng răng bên trong là cho các nội dung của cấu trúc.

Nó xảy ra để làm việc chỉ cung cấp một bộ niềng răng:

two_floats x = {1,2}; 

Nhưng điều này là do một nguyên tắc đặc biệt trong C++ cho phép niềng răng để được bỏ qua trong các trường hợp nhất định. Tương tự như cách bạn có thể khởi tạo một mảng hai chiều với chỉ một bộ niềng răng:

float x[2][2] = {1,2,3,4}; 

Và đây là những gì đang xảy ra khi bạn khởi phạm vi của bạn như thế này:

Range r({1, 2}); 

Đó là tương đương với

std::array<float,2> arg = {1,2}; // one set of braces omittted 
Range r(arg); 

Nhưng đó sẽ rõ ràng hơn được viết như sau:

std::array<float,2> arg = {{1,2}}; 
Range r(arg); 

Điều tương tự cũng xảy ra khi khởi tạo Hộp. Nếu chúng ta một cách rõ ràng viết ra các khởi tạo nó sẽ trông như thế này:

std::array<float,2> box_arg1 = {{1,2}}; 
std::array<float,2> box_arg2 = {{3,4}}; 
std::array<float,2> box_arg3 = {{5,6}}; 
std::array<Range,3> box_args = {{box_arg1,box_arg2,box_arg3}}; 
Box b(box_args); 

Vì vậy, nếu chúng ta thay initializers, chúng tôi nhận được:

Box b({{{{1,2}},{{3,4}},{{5,6}}}}); 

và làm việc. Nhưng nó khá xấu xí. Việc khởi tạo này quá phức tạp để cho phép các dấu ngoặc thừa thừa được bỏ qua ở đây, đó là vấn đề bạn đang gặp phải.

Một cách để giải quyết vấn đề này nhằm cung cấp thêm các nhà thầu có các thành phần mảng riêng lẻ.

class Range 
{ 
public: 
    Range(float x,float y) : m_ends{x,y} { } 
    Range(std::array<float, 2> ends) : m_ends(ends) {} 

private: 
    std::array<float, 2> m_ends; 
}; 

class Box 
{ 
public: 
    Box(Range x,Range y,Range z) : m_ranges{x,y,z} {} 
    Box(std::array<Range, 3> ranges) : m_ranges(ranges) {} 

private: 
    std::array<Range, 3> m_ranges; 
}; 

Và bây giờ bạn có thể khởi tạo Box của bạn như bạn muốn ban đầu:

Box b({{1,2}, {3,4}, {5,6}}); 
0

AFAIK nó không thể được thực hiện với mảng, bạn phải dùng đến loại cơ bản

struct Range 
{ 
    float m_ends[2] ;  
}; 


Range r = {1.0f, 2.0f}; 


struct Box 
{ 
    Range m_ranges[3];  
}; 


Box b = {{{1.0f, 2.0f}, {1.0f, 2.0f}, {1.0f, 2.0f}}}; 
1

Vấn đề

Mã này: Box b({{1,2}, {3,4}, {5,6}}); đang cố gắng aggregate initialize trường hợp của Range mặc dù Range không phải là một tổng hợp.

khởi tổng hợp là một hình thức của danh-khởi, mà khởi uẩn

Một tổng hợp là một trong các loại sau đây:

kiểu mảng

lớp kiểu (thông thường, struct hay union), có

no thành viên dữ liệu không được bảo mật hoặc riêng tư

không dùng cung cấp constructors, kể cả những người được thừa hưởng từ các căn cứ nào (sinceC++ 17) (một cách rõ ràng mặc định hoặc các hàm xóa được phép)

(từ C++ 11) không ảo, tư nhân, hoặc được bảo vệ (từ C++ 17) cơ sở lớp

không hàm thành viên ảo

giải pháp

Gọi constructor của Range explicitcly và chỉ tổng hợp-khởi tạo std::array:

Box b({Range({1,2}), Range({3,4}), Range({5,6})}); 
+1

Nó không phải là tổng hợp khởi tạo, nó đang cố gắng sử dụng [danh sách khởi tạo] (http://en.cppreference.com/w/cpp/language/list_initialization) – user1887915

3

Tôi chỉ sẽ thả các mảng và sử dụng các trường bình thường. Bạn luôn có thể thêm quá tải operator[] nếu bạn thực sự cần. Chỉ cần thay đổi tên trường thành bất kỳ tên nào bạn đang thực sự lập mô hình.

class Range 
{ 
public: 
    Range(float x, float y) : m_x{x}, m_y{y} 
    {} 
private: 
    float m_x, m_y; 
}; 

class Box 
{ 
public: 
    Box(Range w, Range h, Range d) : m_w{w}, m_h{h}, m_d{d} 
    {} 
private: 
    Range m_w, m_h, m_d; 
}; 

Live Demo

+0

Toán tử '[]' sẽ cần một phán đoán 'if', nó có ảnh hưởng đến hiệu suất không? –

1

Bạn có thể có thể sử dụng danh sách initializer:

class Range 
{ 
public: 
    Range(std::initializer_list<float> ends) : m_ends(ends) {} 
    float a() { 
    return m_ends[0]; 
    } 
    float b() { 
    return m_ends[1]; 
    } 

private: 
    std::vector<float> m_ends; 
}; 

class Box 
{ 
public: 
    Box(std::initializer_list<Range> ranges) : m_ranges(ranges) {} 

    void print() 
    { 
    for (auto& i : m_ranges) 
    { 
     std::cout << i.a() << "," << i.b() << std::endl; 
    } 
    } 

private: 
    std::vector<Range> m_ranges; 
}; 


    Range r({ 1,2 }); 
    Box b({ {1,2},{3,4},{5,6} }); 
    b.print(); 

cho

1,2 
3,4 
5,6 
+0

Bạn không quản lý kích thước. – Jarod42

+1

@ Jarod42 đúng, chỉ hiển thị đường dẫn –

0

Để có được một danh sách khởi tạo đúng, danh sách đầu tiên hình thức đầy đủ của nó:

Box b{ 
    array<Range, 3>{{ // std::array needs aggregate-initialize, 
         // and have to initialize a inner array 
         // without a addition '{', C++ is unable to 
         // know that the inner element is Range 
     Range{ 
      {1, 2} // short-hand for array<float>{{3, 4}} 
     }, 
     Range{ 
      {3, 4} 
     }, 
     Range{ 
      {5, 6} 
     } 
    }} 
} 

Hủy bỏ tất cả các loại trừ Box, chúng tôi đã nhận:

Box b{ {{ {{1, 2}}, {{3, 4}}, {{5, 6}} }} }

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