C++ 未定义的引用,带有std::experimental::optional,尽管存在符号

C++ 未定义的引用,带有std::experimental::optional,尽管存在符号,c++,c++14,undefined-reference,libstdc++,stdoptional,C++,C++14,Undefined Reference,Libstdc++,Stdoptional,在我正在进行的一个项目中,我摆弄了一堆CMake设置之后,遇到了一个以前从未遇到过的链接问题 简而言之,我有一个静态库(.a文件),带有以下符号(demangled): tl;dr:这可能是由于在库外的代码中使用自定义可选实现造成的。 我的直觉是正确的,但@1201programalam的评论让我找到了解决方案: 代码> STD::实验::使用静态库的项目中的可选< /代码>不是从标准C++库中获取的。相反,这是一个阴影。现在,我没有什么不好的话要说-它真的很好;但是,它确实将该定义放入了st

在我正在进行的一个项目中,我摆弄了一堆CMake设置之后,遇到了一个以前从未遇到过的链接问题

简而言之,我有一个静态库(
.a
文件),带有以下符号(demangled):

tl;dr:这可能是由于在库外的代码中使用自定义
可选
实现造成的。
我的直觉是正确的,但@1201programalam的评论让我找到了解决方案:

<>代码> STD::实验::使用静态库的项目中的可选< /代码>不是从标准C++库中获取的。相反,这是一个阴影。现在,我没有什么不好的话要说-它真的很好;但是,它确实将该定义放入了
std::experiative
,这意味着如果您不小心,可能会将其误认为是C++14的
std::experiative::optional

在我的例子中,
#if u cplusplus>something
以一种方式定义它,
#else if u cplusplus>something
以另一种方式定义它等等的链是错误的-即使在使用C++14编译时也使用了自定义可选实现

另一方面,链接器不会混淆不同的
可选
实现;事实上,libstdc++的
std::experimental::optional
只是
std::experimental::fundamentals_v1::optional
的别名;因此,返回
可选
的函数的损坏名称是不同的。因此,即使在C++中,也不能在返回类型上重载函数,即除了两种不同的返回类型之外,没有两个函数可以具有相同的签名——没有什么能防止两个被函数化的函数名(IIANM),这就是我的情况。
我现在还不能完全确定的是,我首先是如何避免链接问题的…

如果有a就好了。如果包含a和使用的编译命令,这将改进问题。(如果你能用
g++
命令行在一个文件上复制,这会让事情变得更容易,因为没有人能真正知道你的cmake可能在做什么)@ZhengQu:是的,它会。。。但我问的是潜在原因,而不是实际原因。让我澄清一下。@M.M:好了。在编译器资源管理器上进行的实验表明,gcc的最新版本(我抽查了6.1到9.3)将映射到
std::experiative::optional
std::experiative::basictural\u v1::optional
。我不知道你在你的可执行版本中会做什么来改变这一点。对于函数模板,返回类型包含在损坏的名称中。对于非模板函数,它不是,所以如果你有一个非模板函数返回一个
可选的
,那么它可能会链接并且有无声的未定义行为(因为违反了一个定义规则)。@JonathanWakely:有没有可能通过编译器标志来获得可见性?我不理解这个问题。什么能见度?未定义的行为?@JonathanWakely:我的意思是,可以看到两个函数被链接,这两个函数只在返回类型上不同,不是模板。可以使用
-flto
检测,也可以使用
gold
链接器及其选项
-检测odr冲突
(或类似的东西)。但一般来说,不是。它未定义且格式不正确的原因是实现不可能可靠地检测到它并给出错误。如果可能,它将需要发出诊断,而不仅仅是导致无声的未定义行为。
00000000000018e0 g     F .text  0000000000000690 std::experimental::fundamentals_v1::optional<int> monetdb::gdk::buffer_pool::find_column<(monetdb::column_name_kind)2>(monetdb::column_name<(monetdb::column_name_kind)2> const&) const
main.cpp:(.text+0x6950): undefined reference to `std::experimental::optional<int> monetdb::gdk::buffer_pool::find_column<(monetdb::column_name_kind)2>(monetdb::column_name<(monetdb::column_name_kind)2> const&) const'
Using built-in specs.
COLLECT_GCC=g++-8
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 8.3.0-22' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto --enable-link-mutex
Thread model: posix
gcc version 8.3.0 (Debian 8.3.0-22)