2012-09-15 55 views
20

tôi đã cố gắng để biên dịch các đoạn sau đây với gcc4.7vector tuple và initializer_list

vector<pair<int,char> > vp = {{1,'a'},{2,'b'}}; 
//For pair vector, it works like a charm. 

vector<tuple<int,double,char> > vt = {{1,0.1,'a'},{2,4.2,'b'}}; 

Tuy nhiên, đối với các vector của các bộ, trình biên dịch phàn nàn:

lỗi: chuyển đổi để 'std :: tuple 'từ danh sách initializer sẽ sử dụng constructor rõ ràng' constexpr std :: tuple <> :: tuple (_UElements & & ...) [với _UElements = {int, double, char}; = void; _Elements = {int, double, char}] '

Thông tin lỗi bị tràn bởi trình biên dịch là tổng số vô nghĩa đối với tôi và tôi không biết các nhà thầu xây dựng bộ tuple được thực hiện như thế nào, nhưng tôi biết họ hoàn toàn ổn với khởi tạo thống nhất (như: tuple<int,float,char>{1,2.2,'X'}), do đó, tôi tự hỏi nếu vấn đề tôi gặp phải chỉ là một TODO của trình biên dịch hoặc nó là một cái gì đó được xác định bởi tiêu chuẩn C++ 11.

Bất kỳ phản hồi nào sẽ được đánh giá cao!

Trả lời

25

Nếu bạn kiểm tra reference page trên constructor tuple, bạn sẽ thấy rằng không mất std::initializer_list cần thiết để lớp có thể chấp nhận danh sách trình khởi tạo.

Bạn khởi tạo vector với std::make_tuple:

vector<tuple<int,double,char>> vt = 
    { std::make_tuple(1,0.1,'a'), std::make_tuple(2,4.2,'b') }; 
+0

Lấy làm tiếc! Tôi đã thực hiện một lỗi đánh máy, chỉnh sửa lại, nhưng vẫn không hoạt động! – Need4Steed

+0

@ Need4Steed Đã cập nhật câu trả lời của tôi. –

+0

Tôi đã thử make_tuple, nó hoạt động tốt, nhưng nó có vẻ không phù hợp với tôi nếu nó ổn với cặp nhưng không đi với tuple. – Need4Steed

5

Các std::tuple nhà xây dựng có liên quan explicit. Điều này có nghĩa rằng những gì bạn muốn làm là không thể, vì cú pháp bạn muốn sử dụng được xác định trong điều khoản của khởi tạo sao chép (mà cấm gọi một constructor explicit). Ngược lại, std::tuple<int, float, char> { 1, 2.2, 'X' } sử dụng khởi tạo trực tiếp. std::pair chỉ có explicit nhà thầu.

Hoặc sử dụng trực tiếp khởi tạo hoặc một trong các tiêu chuẩn chức năng nhà máy tuple (ví dụ std::make_tuple).

0

Điều này thực sự có thể thực hiện được, với các tính năng C++ 11.

Có initializer_list muốn tất cả phần tử của nó phải cùng loại. Bí quyết là chúng ta có thể tạo ra một lớp wrapper mà có thể static_cast cho tất cả các loại chúng ta muốn. Đây là dễ dàng để đạt được:

template <typename... tlist> 
class MultiTypeWrapper { 
}; 

template <typename H> 
class MultiTypeWrapper<H> { 
public: 
    MultiTypeWrapper() {} 

    MultiTypeWrapper(const H &value) : value_(value) {} 

    operator H() const { 
    return value_; 
    } 
private: 
    H value_; 
}; 

template <typename H, typename... T> 
class MultiTypeWrapper<H, T...> 
    : public MultiTypeWrapper<T...> { 

public: 
    MultiTypeWrapper() {} 

    MultiTypeWrapper(const H &value) : value_(value) {} 

    // If the current constructor does not match the type, pass to its ancestor. 
    template <typename C> 
    MultiTypeWrapper(const C &value) : MultiTypeWrapper<T...>(value) {} 

    operator H() const { 
    return value_; 
    } 
private: 
    H value_; 
}; 

Với các nhà thầu chuyển đổi ngầm, chúng ta có thể vượt qua một cái gì đó như {1,2.5, 'c', 4} để một initializer_list (hoặc vector, mà mặc nhiên chuyển đổi initializer_list) loại MultiTypeWrapper. Điều này có nghĩa rằng chúng ta không thể viết một hàm như dưới chấp nhận intializer_list như lập luận:

template <typename... T> 
std::tuple<T...> create_tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) { 
    .... 
} 

Chúng tôi sử dụng thủ thuật khác để cast mỗi giá trị trong các vector để loại ban đầu của nó (lưu ý rằng chúng tôi cung cấp chuyển đổi ngầm trong định nghĩa của MultiTypeWrapper) và gán nó vào vị trí tương ứng trong một bộ tuple. Nó giống như một đệ quy trên lập luận mẫu:

template <int ind, typename... T> 
class helper { 
public: 
    static void set_tuple(std::tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) { 
    std::get<ind>(t) = static_cast<typename std::tuple_element<ind,std::tuple<T...> >::type>(v[ind]); 
    helper<(ind-1),T...>::set_tuple(t,v); 
    } 
}; 



template <typename... T> 
class helper<0, T...> { 
public: 
    static void set_tuple(std::tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) { 
    std::get<0>(t) = static_cast<typename std::tuple_element<0,std::tuple<T...> >::type>(v[0]); 
    } 
}; 



template <typename... T> 
std::tuple<T...> create_tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) { 
    std::tuple<T...> res; 
    helper<sizeof...(T)-1, T...>::set_tuple(res, init); 
    return res; 
} 

Lưu ý rằng chúng ta phải tạo ra các lớp helper cho set_tuple từ C++ không hỗ trợ chức năng chuyên môn.Bây giờ nếu chúng ta muốn kiểm tra mã:

auto t = create_tuple<int,double,std::string>({1,2.5,std::string("ABC")}); 
printf("%d %.2lf %s\n", std::get<0>(t), std::get<1>(t), std::get<2>(t).c_str()); 

Kết quả sẽ là:

1 2.50 ABC 

này được thử nghiệm trên máy tính để bàn của tôi với kêu vang 3.2

Hy vọng đầu vào của tôi giúp :)

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