【问题标题】:optional and variant with gcc 4.7gcc 4.7 的可选和变体
【发布时间】:2018-07-06 08:14:31
【问题描述】:

我有应该用 gcc 4.7 编译的代码, 对c++11的支持还不错,但是缺少c++14和c++17。

我想在我的代码中使用std::optionalstd::variant, 为 gcc 4.7 提供 boost::optionalboost::variant 的后备

实现这一目标的标准方法是什么?

我看到两种变体:

  1. 包装变体,它可能是宏,如:#define VARIANT_TYPE boost::variantnamespace my_code { using variant = boost::variant }
  2. 扩展std命名空间

第一个不好,因为我的代码会使用my_code::variant, 而不是std::variant。第二个对我来说看起来更清楚。

2 在一般情况下可能是 UB What are the reasons that extending the std namespace is considered undefined behavior?

但是我的具体情况呢?我知道gcc 的确切版本有variant/optional,我可以在构建的配置阶段检查它。对于所有其他编译器/标准 c++ 库,我可以要求 c++17 支持,而不是使用我将 boost::optional 转换为 std::optional 的技巧。

我还能发现一些奇特的问题吗?

【问题讨论】:

  • 切换实现的意义何在?只需无条件使用 boost。
  • 我会做using variant_type = std::variant;。为此避免使用宏。此外,除非标准允许,否则永远不要扩展 std
  • @HolyBlackCat 因为它是库,我不想为拥有c++17 兼容编译器的用户创建对 boost 的外部依赖。
  • @Galik 但对于特定的编译器和 libstdc++ 不适用于一般情况

标签: c++ c++11 gcc boost


【解决方案1】:

你可能会使用类似的东西:

#ifdef NEED_WORKAROUND

# include <boost/optional.hpp>
# include <boost/variant.hpp>

namespace workaround
{
    namespace std
    {
        using boost::optional;
        using boost::variant;
    }
}
using namespace workaround;
#else
# include <optional>
# include <variant>
#endif

所以使用::std::variant&lt;..&gt; 将不起作用
但简单的std::variant&lt;..&gt; 的行为大多相似(您可能对 ADL 有疑问)。

【讨论】:

  • 您为什么会对 ADL 有任何问题? using-declarations 不会以任何方式影响 ADL。 using-directives 仅对它产生影响,以至于它们可能会将名称带入 ADL 关联的范围内(例如在调用没有关联命名空间的原始类型的函数时)
  • @sehe: 例如对于像这样的代码:find(carray, carray+N, std::optional&lt;int&gt;(42)) 我们不需要std::find(没有解决方法,但我们需要它)。所以有一个“问题”。
【解决方案2】:

接近你想要的一种方法是找到一个为你做这件事的图书馆。

例如,Google's Abseil 就是这样做的。不幸的是,他们的Supported Platforms 页面显示他们需要 gcc 4.8+,因为他们需要 C++11。但是如果你能满足他们的要求,那么你可以用absl::optional代替std::optional,如果std::optional存在,那么absl::optional就是std::optional,否则就相当于std::optional

你写absl::optional而不是std::optional是无关紧要的;您的代码库的读者可以很容易地了解到它们是“相同的东西”。我强烈建议不要尝试将其放入 std 命名空间。


自己这样做是不愉快的,但并非不可能。你需要两件事:

  • 判断std::optional是否存在的方法
  • 在另一个命名空间中实现std::optional,它适用于您要支持的编译器版本(请注意,boost 版本不一定完全等同于std 版本)

然后,您可以像选项 1 一样编写解决方法,并编写如下内容:

#if STD_OPTIONAL_EXISTS

namespace compat {
    template <typename... Ts>
    using optional = std::optional<Ts...>;
}

#else

namespace compat {
    template <typename... Ts>
    using optional = boost::optional<Ts...>;
}

#endif

【讨论】:

    猜你喜欢
    • 2012-08-03
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多