未定义对extern模板constexpr构造函数的引用

时间:2019-07-10 04:47:24

标签: c++ templates constexpr

这是我可以产生的显示这种行为的最小示例:

  

foo.h

#pragma once

#include <string>

template <int I>
struct foo
{
    constexpr explicit foo(int k)
        : j(k + I)
    { }

    std::string to_string() const;

private:

    int j;
};

extern template struct foo<0>;

constexpr foo<0> operator"" _foo0(unsigned long long int v)
{
    return foo<0>(static_cast<int>(v));
}
  

foo.cpp

#include "foo.h"

template <int I>
std::string foo<I>::to_string() const
{
    return std::to_string(j);
}

template struct foo<0>;
  

bar.h

#pragma once

#include "foo.h"
#include <vector>

template <typename T>
struct bar
{
    explicit bar(int i);

private:

    std::vector<T> vec;
};

extern template struct bar<foo<0>>;
  

bar.cpp

#include "bar.h"

template <typename T>
bar<T>::bar(int i)
{
    vec.push_back(T{i});
}

template struct bar<foo<0>>;

它的用法如下:

  

main.cpp

#include "bar.h"

int main()
{
    bar<foo<0>> b2(5);
}

按照GCC进行编译(我尝试过7.4.0和8.3.0):

g++-8 foo.cpp bar.cpp main.cpp -std=c++14 -Wall -Werror -o test

给出错误:

  

bar.cpp :(。text._ZN3barI3fooILi0EEEC2Ei [_ZN3barI3fooILi0EEEC5Ei] + 0x3c):对foo <0> :: foo(int)的未定义引用

Clang 4至7版似乎接受了这一点。

GCC接受了两个小更改:

  1. 删除constexpr operator""定义,或
  2. operator""foo构造函数都更改为inline而不是constexpr

这合法吗?海湾合作委员会是否有正当理由拒绝该原状?

1 个答案:

答案 0 :(得分:1)

我对您的消息来源进行了很多尝试,并获得了以下结果:

gcc9.1.0编译没有任何问题!

现在对gcc 8.3.0感到好奇:

g++ main.cpp foo.cpp bar.cpp -std=c++14 -Wall // fails: undef reference

失败了!

但没有-Wall可以编译!

g++ main.cpp foo.cpp bar.cpp -std=c++14  // compiles, no linker error!

还有

g++ main.cpp foo.cpp bar.cpp -std=c++17 -Wall // compiles, no linker error!

我不知道为什么标志-Wall与生成的中间文件有任何关系。 -Wall绝不影响任何生成的代码,因为它只是诊断。所以对我来说,这只是一个gcc错误!因此,请填写错误报告!