2017-05-13 20 views
13

Các mã sau biên dịch tốt:C++ 17 biến thể <any> bên trong lớp

int main() 
{ 
    variant<any> var; 
    var = 5; 
    cout << any_cast<int>(get<any>(var)) << endl; 
    return 0; 
} 

Nhưng khi tôi đang cố gắng để đưa variant<any> như một thành viên lớp

struct MyClass{ 
    variant<any> var; 
}; 

int main() 
{ 
    MyClass s; 
    return 0; 
} 

Nó không biên dịch . Tôi đang làm điều gì đó sai hay là một số lỗi?

Tôi đang sử dụng gcc 7.1.0

In file included from /home/zak/Projects/Anytest/main.cpp:3:0: 
/usr/local/gcc-7.1/include/c++/7.1.0/variant: In instantiation of ‘struct std::__detail::__variant::__accepted_index<const std::variant<std::any>&, std::variant<std::any>, void>’: 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:911:26: required from ‘constexpr const size_t std::variant<std::any>::__accepted_index<const std::variant<std::any>&>’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:940:6: required by substitution of ‘template<class _Tp, class> constexpr std::variant<std::any>::variant(_Tp&&) [with _Tp = const std::variant<std::any>&; <template-parameter-1-2> = <missing>]’ 
/home/zak/Projects/Anytest/main.cpp:14:13: required from here 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:559:49: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’ 
     decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()), 
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}] 
     static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First); 
                  ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}] 
    { static void _S_fun(); }; 
        ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:559:49: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’ 
     decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()), 
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}] 
     static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First); 
                  ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}] 
    { static void _S_fun(); }; 
        ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:559:49: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’ 
     decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()), 
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}] 
     static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First); 
                  ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}] 
    { static void _S_fun(); }; 
        ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided 
/usr/local/gcc-7.1/include/c++/7.1.0/variant: In instantiation of ‘constexpr const size_t std::__detail::__variant::__accepted_index<const std::variant<std::any>&, std::variant<std::any>, void>::value’: 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:911:26: required from ‘constexpr const size_t std::variant<std::any>::__accepted_index<const std::variant<std::any>&>’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:940:6: required by substitution of ‘template<class _Tp, class> constexpr std::variant<std::any>::variant(_Tp&&) [with _Tp = const std::variant<std::any>&; <template-parameter-1-2> = <missing>]’ 
/home/zak/Projects/Anytest/main.cpp:14:13: required from here 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:564:12: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’ 
    - decltype(__overload_set<_Types...>:: 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     _S_fun(std::declval<_Tp>()))::value; 
     ~~~~~~^~~~~~~~~~~~~~~~~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}] 
     static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First); 
                  ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}] 
    { static void _S_fun(); }; 
        ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided 
+3

Điều thú vị đủ, thay thế khởi tạo mặc định bằng khởi tạo giá trị, làm cho mã biên dịch tốt trên GCC. http://coliru.stacked-crooked.com/a/d45087050b803e45 – StoryTeller

+3

Xóa trình tạo bản sao cũng làm cho việc biên dịch mã: http://coliru.stacked-crooked.com/a/a7481101122a17a0 –

+1

Soạn ví dụ thứ hai với Visual Studio 2017 và cờ '/ std: C++ latest' hoạt động hoàn hảo. Hoặc GCC đi lên, hoặc MSVC may mắn. Tôi sẽ kiểm tra thêm ... – InternetAussie

Trả lời

10

Vấn đề là với MyClass 's copy constructor ngầm định, khi nó cố gắng để sao chép xây dựng các thành viên của loại std::variant<std::any>.

Để thực hiện độ phân giải quá tải, trình biên dịch đầu tiên cần cố gắng tạo nhanh tất cả các mẫu của hàm tạo std::variant, với đối số hàm là const std::variant<std::any>& . Các nhà xây dựng quan tâm của chúng tôi là một trong những điều này:

template <class T> constexpr variant(T&& t) noexcept(/*...*/); 

Nó chỉ tham gia ở độ phân giải quá tải nếu, trong số những người khác, khái niệm FUN(​std​::​forward<T>(t)) được cũng được hình thành, nơi FUN là một tập hợp các chức năng quá tải được sản xuất theo [variant.ctor]/12.

Trong trường hợp này, chỉ có một loại thay thế (std::any), do đó chỉ có một chức năng tưởng tượng FUN, có chữ ký là FUN(std::any). Bây giờ, trình biên dịch cần phải quyết định xem FUN có thể được gọi với một số const std::variant<std::any>& hay không. Trong quá trình này, trình biên dịch cần phải biết liệu std::any có thể được xây dựng với const std::variant<std::any>& .

này sẽ kích hoạt instantiation của std::any 's constructor mẫu template<class T> any(T&& value);, mà chỉ tham gia vào giải quyết tình trạng quá tải nếu std::is_­copy_­constructible_­v<VT>true (VTstd::decay_t<T>, và Tconst std::variant<std::any>&).

Bây giờ để xem liệu VT (tức std::variant<std::any>) là sao chép constructible, trình biên dịch cần phải cố gắng để nhanh chóng tất cả các mẫu nhà xây dựng std::variant 's ... và đây là nơi mà chúng tôi bắt đầu, và chúng tôi đang bị mắc kẹt trong một vòng lặp .

Điều này có thể giải thích tại sao chúng tôi thấy template<class _Tp, class> constexpr std::variant<std::any>::variant(_Tp&&)__overload_set<std::any>::_S_fun (tương ứng với chức năng FUN được đề cập ở trên) trong thông báo lỗi và lý do tại sao chúng tôi thấy cùng một lỗi xuất hiện nhiều lần.

Nó vẫn là một câu hỏi làm thế nào GCC phá vỡ từ vòng lặp trên, và tại sao tinh chỉnh chương trình có thể ngăn chặn GCC báo cáo lỗi. Có lẽ đây là dấu hiệu của một số lỗi.


1. Nói đúng ra, nó phải là "một vế trái của loại const std::variant<std::any>" hơn là "một const std::variant<std::any>&".

2. Tiêu chuẩn cũng yêu cầu hàm tạo này chỉ tham gia vào độ phân giải quá tải nếu is_­same_­v<decay_­t<T>, variant>false. GCC (libstdC++) chọn để kiểm tra sau này. Tôi không biết liệu điều này có phù hợp hay không.

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