Boost可选和用户定义的转换

boost optional and user-defined conversion

本文关键字:定义 转换 用户 Boost      更新时间:2023-10-16

我无法为类型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结构构造函数,而不是使用用户定义的转换操作符?

你可以直接指向用户定义转换页面的任何位置,因为我找不到任何原因。例如,

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

在我看来,

直接表示,如果没有定义转换构造函数,则使用用户定义的转换函数。我错了吗?如果是,我如何实现用户定义的转换,然后不定义转换构造函数在struct A ?

您的代码有两个问题。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);