提升可选和用户定义的转化

时间:2015-10-22 13:22:21

标签: c++ c++11 boost type-conversion

我无法为类型Item编写正确的用户定义转换。这就是我尝试过的:

#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结构构造函数而不是使用用户定义的转换运算符?

您可以直接将我指向user-defined conversion页面的任何位置,因为我无法找到任何理由。例如,

  

在隐式转换的第二阶段调用用户定义的转换函数,该转换函数由零个或一个转换构造函数零或一个用户定义的转换函数组成。

在我看来,

直接说如果没有定义转换构造函数,那么将使用用户定义的转换函数。我错了吗?如果是,我如何实现用户定义的转换,而无需在struct A中定义转换cunstructor?

1 个答案:

答案 0 :(得分: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);

这还有一个额外的好处,也更容易阅读。