2015-10-22 3 views
1

Я не могу написать правильное преобразование, определенное пользователем для типа Item. Это то, что я пробовал:boost опционально и пользовательское преобразование

#include <iostream> 
#include <boost/optional.hpp> 
struct A 
{ 
    int x; 
}; 

struct Item 
{ 
    boost::optional<int> x_; 

    Item(){} 
    Item(const A& s) 
    : x_(s.x) 
    { 
    } 

    operator boost::optional<A>() const { 
     boost::optional<A> s; 
     if (x_) { 
      s->x = *x_; 
     } 
     return s; 
    } 
}; 

std::vector<A> getA(const std::vector<Item> &items) { 
    std::vector<A> a; 
    for (const auto &i : items) { 
     if (i.x_) { 
      a.push_back(*static_cast<boost::optional<A>>(i)); // <- this line causes error 
     } 
    } 
    return a; 
} 

То есть, как я использую его:

int main() { 
    A a; 
    a.x = 3; 
    Item i(a); 
    auto v = getA({i}); 

    return 0; 
} 

g++ -std=c++11 говорит:

In file included from /usr/include/boost/optional.hpp:15:0, 
       from test.cpp:2: 
/usr/include/boost/optional/optional.hpp: In instantiation of ‘void boost::optional_detail::optional_base<T>::construct(const Expr&, const void*) [with Expr = Item; T = A]’: 
/usr/include/boost/optional/optional.hpp:262:25: required from ‘boost::optional_detail::optional_base<T>::optional_base(const Expr&, const Expr*) [with Expr = Item; T = A]’ 
/usr/include/boost/optional/optional.hpp:559:78: required from ‘boost::optional<T>::optional(const Expr&) [with Expr = Item; T = A]’ 
test.cpp:30:55: required from here 
/usr/include/boost/optional/optional.hpp:392:8: error: no matching function for call to ‘A::A(const Item&)’ 
     new (m_storage.address()) internal_type(expr) ; 
     ^
/usr/include/boost/optional/optional.hpp:392:8: note: candidates are: 
test.cpp:3:8: note: A::A() 
struct A 
     ^
test.cpp:3:8: note: candidate expects 0 arguments, 1 provided 
test.cpp:3:8: note: constexpr A::A(const A&) 
test.cpp:3:8: note: no known conversion for argument 1 from ‘const Item’ to ‘const A&’ 
test.cpp:3:8: note: constexpr A::A(A&&) 
test.cpp:3:8: note: no known conversion for argument 1 from ‘const Item’ to ‘A&&’ 

Почему пытаются найти A STRUCT конструктор вместо использовать пользовательский оператор преобразования?

Вы можете указать мне прямо в любую позицию страницы user-defined conversion, потому что я не могу найти повод для этого. Например,

определяемого пользователь функция преобразования вызывается на втором этапе неявного преобразования, который состоит из ноля или один преобразования конструктору или ноля или один определенного пользователем функции преобразования.

, на мой взгляд, прямо говорит, что если конструктор преобразования не задан, будет использоваться пользовательская функция преобразования. Я ошибаюсь? И если да, как я могу реализовать пользовательское преобразование, то без определения конверсионного cunstructor в struct A?

ответ

1

У вас есть две проблемы с кодом. Ваш оператор optional никогда не инициализирует boost::optional. Если вы этого не сделаете, доступ к членам - это неопределенное поведение. То, что вы должны сделать, это:

operator boost::optional<A>() const { 
    boost::optional<A> s; 
    if (x_) { 
     s = A{*x_}; 
    } 
    return s; 
} 

Вторая проблема, когда вы делаете:

static_cast<boost::optional<A>>(i); 

Это эквивалентно:

boost::optional<A> __tmp(i); 

Но оказывается, что boost::optional имеет explicit конструктор шаблонов. Это будет предпочтительнее для вашей функции преобразования. Ошибка, которую вы видите, - это компиляция, идущая вниз по пути этого заводского конструктора, где Item не является такой фабрикой.

Вы могли бы просто использовать boost::optional<A> непосредственно:

std::vector<A> getA(const std::vector<Item> &items) { 
    std::vector<A> a; 
    for (boost::optional<A> opt : items) { 
     if (opt) { 
      a.push_back(*opt); 
     } 
    } 
    return a; 
} 

Или, так как шаблон конструктор explicit, вы можете использовать оператор преобразования в не явном контексте:

boost::optional<A> opt = i; 
a.push_back(*opt); 

Это имеет Кроме того, было легче читать.

+0

К сожалению, при перемещении кода для тестирования забыл инициализировать его, спасибо. О фактическом ответе - что, если мне нужно проверить некоторые поля или просто сделать что-то с объектом 'Item', прежде чем преобразовать его в boost: optional '? Ваш ответ использует 'boost :: optional ' с самого начала, но я хочу это сделать позже после некоторой работы с 'Item'. –

Смежные вопросы