使用std :: max会导致链接错误?

时间:2017-12-16 03:02:16

标签: c++11

考虑在头文件中定义的库

<Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Button"
    android:theme="@style/PrimaryDarkButton" />

库被编译,我现在正在开发一个链接到这个库的应用程序。我想很长一段时间它都是某种可见性问题,但即使在无处不在的地方添加struct Proj { struct Depth { static constexpr unsigned Width = 10u; static constexpr unsigned Height = 10u; }; struct Video { static constexpr unsigned Width = 10u; static constexpr unsigned Height = 10u; }; }; (来自CMake的标准可见性内容)之后,我终于找到了问题。

B_EXPORT

我甚至无法使用小型虚拟库/示例应用程序重现该问题。但是在应用程序中使用template <class Projection> struct SomeApplication { SomeApplication() { unsigned height = std::max(// or std::max<unsigned> Projection::Depth::Height, Projection::Video::Height ); } }; 会导致链接错误,而如果我自己执行此操作

std::max

一切顺利。就使用unsigned height = Projection::Depth::Height; if (height < Projection::Video::Height) height = Projection::Video::Height; 而言,可见性方面似乎没有任何具体问题。

有关可能导致此问题的任何想法?这是在OSX上,所以this doesn't even apply

1 个答案:

答案 0 :(得分:1)

问题是WidthHeight 已声明,而不是struct已定义。实际上,这意味着没有为他们分配存储空间。

现在回想一下std::max的签名:

template<typename T>
const T& max(const T&, const T&);

注意引用:这意味着要采用参数的地址。但是,由于WidthHeight仅被声明,因此它们没有任何存储空间!因此链接器错误。

现在让我们考虑你的其余问题。

您手写的max有效,因为您从不接受任何指针或对变量的引用。

您可能无法在玩具示例中重现这一点,因为特别是根据优化级别,足够智能的编译器可能会在编译时评估max并省去在运行时获取地址的麻烦。例如,比较gcc 7.2的no optimization-O2的dis:评估确实是在编译时完成的!

至于修复,取决于。您有几个选项,仅举几例:

  1. 使用constexpr getter函数代替变量。在这种情况下,它们返回的值将更像临时对象,允许采用地址(并且编译器肯定会对其进行优化)。这是我一般建议的方法。
  2. 使用命名空间而不是结构。在这种情况下,除了声明之外,还将定义变量。需要注意的是,如果在多个翻译单元中使用它们,则可能会出现重复的符号错误。对此的修复只是以C ++ 17内联变量的形式。
  3. ...说到这一点,C ++ 17也改变了constexpr静态成员变量的规则(默认情况下它们变为内联),所以如果你只是切换到这个标准就不会出现这个错误。