Boost.Variant、Boost.MPL:如何追加类型?

发布于 2024-12-18 15:10:34 字数 4222 浏览 1 评论 0原文

我看着这个基于 boost.Any 的代码,不禁想知道我们是否可以使用Boost.Variant 代替。我想知道这样的 API 是否可行:

void voidFunc()
{
    std::cout << "void called" << std::endl;
}

int stringFunc(std::string str)
{
    std::cout << str << std::endl;
    return 0;
}

int main()
{
    some_map_like_type<std::string, boost::variant> funcs;
    funcs.insert<void , void >("voidFunc", &voidFunc)); // now our variant vould contain something like boost::function<void, void>
    funcs.insert<int , std::string>("stringFunc", &stringFunc)); // and now we added to our variant a new type: boost::function<int , std::string>
    funcs.insert<void , void >("voidFunc2", &voidFunc)); // and now our variant should not change because it already contains boost::function<void, void> type


    // And here when all the fun part is:
    funcs["voidFunc"](); // compiles
    funcs["stringFunc"]("hello"); // compiles
    funcs["stringFunc"](some_not_std_string_class); // does not compile.
    return 0;
}

这意味着最后编译器必须编译如下内容:

void voidFunc()
{
    std::cout << "void called" << std::endl;
}

int stringFunc(std::string str)
{
    std::cout << str << std::endl;
    return 0;
}

int main()
{
    some_map_like_type<std::string, boost::variant< boost::function<void , void>, boost::function<int , std::string> > > funcs;
    funcs.insert<void , void >("voidFunc", &voidFunc)); // now our variant vould contain something like boost::function<void, void>
    funcs.insert<int , std::string>("stringFunc", &stringFunc)); // and now we added to our variant a new type: boost::function<int , std::string>
    funcs.insert<void , void >("voidFunc2", &voidFunc)); // and now our variant should not change because it already contains boost::function<void, void> type


    // And here when all the fun part is:
    funcs["voidFunc"](); // compiles
    funcs["stringFunc"]("hello"); // compiles
    funcs["stringFunc"](some_not_std_string_class); // here it would give error and would not compile
    return 0;
}

更新:

我尝试过什么(基于此 变体文档 和这个 MPL 演示docs):

#include <boost/static_assert.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/multiplies.hpp>
#include <boost/mpl/placeholders.hpp>

#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include <vector>

class sudo_science
{
public:
    typedef  boost::mpl::vector_c<int> types_vector1;

    typedef boost::make_recursive_variant< types_vector1 >::type recursive_variant_t;

    std::vector< recursive_variant_t > variant_seq;

    template <typename T>
    void append(T val)
    {
        typedef  boost::mpl::push_back<types_vector1,T>::type types_vector1;
        variant_seq.push_back(val);
        return;
    }

    std::vector< recursive_variant_t > give_me_end_variant()
     {
         return variant_seq;
     }
};

int main()
{
    sudo_science a;
    a.append<float>(1.0);
    a.append<std::string>("Stack and Boost");

    //sorry for C++11
    auto varint = a.give_me_end_variant();

    return 0;
}

但它无法编译,并出现 2 个相同的错误:

Error   1   error C2665: 'boost::detail::variant::make_initializer_node::apply<BaseIndexPair,Iterator>::initializer_node::initialize' : none of the 2 overloads could convert all the argument types    c:\program files\boost\include\boost\variant\variant.hpp    1330    1

I look at this grate code based on boost.Any and cant help but wonder if we could use Boost.Variant instead. I wonder if such API would be possible:

void voidFunc()
{
    std::cout << "void called" << std::endl;
}

int stringFunc(std::string str)
{
    std::cout << str << std::endl;
    return 0;
}

int main()
{
    some_map_like_type<std::string, boost::variant> funcs;
    funcs.insert<void , void >("voidFunc", &voidFunc)); // now our variant vould contain something like boost::function<void, void>
    funcs.insert<int , std::string>("stringFunc", &stringFunc)); // and now we added to our variant a new type: boost::function<int , std::string>
    funcs.insert<void , void >("voidFunc2", &voidFunc)); // and now our variant should not change because it already contains boost::function<void, void> type


    // And here when all the fun part is:
    funcs["voidFunc"](); // compiles
    funcs["stringFunc"]("hello"); // compiles
    funcs["stringFunc"](some_not_std_string_class); // does not compile.
    return 0;
}

That means that at the end compiler would have to compile something like:

void voidFunc()
{
    std::cout << "void called" << std::endl;
}

int stringFunc(std::string str)
{
    std::cout << str << std::endl;
    return 0;
}

int main()
{
    some_map_like_type<std::string, boost::variant< boost::function<void , void>, boost::function<int , std::string> > > funcs;
    funcs.insert<void , void >("voidFunc", &voidFunc)); // now our variant vould contain something like boost::function<void, void>
    funcs.insert<int , std::string>("stringFunc", &stringFunc)); // and now we added to our variant a new type: boost::function<int , std::string>
    funcs.insert<void , void >("voidFunc2", &voidFunc)); // and now our variant should not change because it already contains boost::function<void, void> type


    // And here when all the fun part is:
    funcs["voidFunc"](); // compiles
    funcs["stringFunc"]("hello"); // compiles
    funcs["stringFunc"](some_not_std_string_class); // here it would give error and would not compile
    return 0;
}

Update:

What have I tried (based on this Variant docs and this MPL demos and docs):

#include <boost/static_assert.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/multiplies.hpp>
#include <boost/mpl/placeholders.hpp>

#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include <vector>

class sudo_science
{
public:
    typedef  boost::mpl::vector_c<int> types_vector1;

    typedef boost::make_recursive_variant< types_vector1 >::type recursive_variant_t;

    std::vector< recursive_variant_t > variant_seq;

    template <typename T>
    void append(T val)
    {
        typedef  boost::mpl::push_back<types_vector1,T>::type types_vector1;
        variant_seq.push_back(val);
        return;
    }

    std::vector< recursive_variant_t > give_me_end_variant()
     {
         return variant_seq;
     }
};

int main()
{
    sudo_science a;
    a.append<float>(1.0);
    a.append<std::string>("Stack and Boost");

    //sorry for C++11
    auto varint = a.give_me_end_variant();

    return 0;
}

But it fails to compile with 2 same errors:

Error   1   error C2665: 'boost::detail::variant::make_initializer_node::apply<BaseIndexPair,Iterator>::initializer_node::initialize' : none of the 2 overloads could convert all the argument types    c:\program files\boost\include\boost\variant\variant.hpp    1330    1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一瞬间的火花 2024-12-25 15:10:34

这是不可能的。 operator[] 是运行时的事情,而类型是编译时的事情。那么编译器应该编译以下内容吗?

char const* str;
if (some_condition())
  str = "voidFunc";
else
  str = "stringFunc";
// ... some more code
if (some_condition())
  funcs[str]();
else
  funcs[str](str);

编译器如何知道第二次调用 some_condition() 是否给出与之前相同的结果?或者中间的代码是否修改了str的值?

那么以下情况如何:

void call(some_map_like_type<std::string, boost::variant> const& funcs)
{
  funcs["voidFunc"]();
}

编译器如何知道在调用时 funcs 是否包含将 "voidFunc" 映射到不带参数的函数的条目?如果用一个值调用它一次,又用一个不调用值调用一次,会发生什么情况?

根据您实际想要实现的目标,可能有一种方法可以通过模板和 constexpr 函数来实现。但请注意,运行时发生的任何事情都不会影响代码是否编译,原因很简单,代码在编译之前无法运行。

It is not possible. operator[] is a run-time thing, while types are a compile-time thing. So should the compiler compile the following?

char const* str;
if (some_condition())
  str = "voidFunc";
else
  str = "stringFunc";
// ... some more code
if (some_condition())
  funcs[str]();
else
  funcs[str](str);

How is the compiler supposed to know whether the second call to some_condition() gives the same result as before? Or whether the code in between modified the value of str?

What about the following:

void call(some_map_like_type<std::string, boost::variant> const& funcs)
{
  funcs["voidFunc"]();
}

How is the compiler supposed to know whether at call time funcs contains an entry mapping "voidFunc"to a function with no arguments? And what should happen if it is called once on with a value that does, and once with a value which doesn't?

Depending on what you actually want to achieve, there might be a way to get it with templates and constexpr functions. However note that nothing which happens at runtime can affect whether the code compiles, for the simple reason that the code cannot be run before it is compiled.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文