You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

clang++ 18下含requires表达式的模板函数出现未定义引用,代码是否合法?

这段带requires约束的模板代码是否符合C++标准?

问题描述

我编写了一段测试代码,在g++ 13.2及clang++ 17及以下版本均可正常编译链接,但使用clang++ 18编译时失败,出现未定义引用错误。通过nm工具查看发现,clang++ 18将requires条件纳入了导出符号名称中,而旧版本并未如此。请问这段代码是否符合C++标准?

测试代码

test.cpp

#include "test.hpp"

#include <optional>
#include <stdio.h>
#include <string>

template<class T>
    requires(!std::is_same_v<T, std::string>)
std::optional<T> myFunction(std::string arg) {
    return std::optional<T>{};
}

template std::optional<int> myFunction<int>(std::string arg);

test.hpp

#pragma once

#include <optional>
#include <string>

template<class T>
std::optional<T> myFunction(std::string arg);

main.cpp

#include "test.hpp"

#include <optional>

int main()
{
    std::optional<int> foobar = myFunction<int>("foobar");
}

复现步骤

#!/bin/sh -x

clang++-18 --version
clang++-18 -std=c++20 -c test.cpp -o test-clang.o
clang++-18 -std=c++20 -c main.cpp -o main-clang.o
clang++-18 main-clang.o test-clang.o -o main-clang

编译报错信息

/usr/bin/ld: main-clang.o: in function main': main.cpp:(.text+0x2f): undefined reference to std::optional myFunction(std::__cxx11::basic_string<char, std::char_traits, std::allocator >)'
clang++-19: error: linker command failed with exit code 1 (use -v to see invocation)

nm工具对比结果

clang++ 17生成的符号

$ nm --demangle test-clang-17.o | grep -i myFunc
0000000000000000 W std::optional<int> myFunction<int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)

clang++ 18生成的符号

$ nm --demangle test-clang-18.o | grep -i myFunc
0000000000000000 W std::optional<int> myFunction<int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) requires !(std::is_same_v<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >)

解答

这段代码不符合C++标准。

C++标准要求:模板的所有声明(包括头文件中的声明)必须与定义保持完全一致,包括模板的约束条件(requires子句)。在你的代码中,头文件test.hpp里的myFunction模板声明没有包含requires(!std::is_same_v<T, std::string>)约束,而test.cpp中的模板定义却带有这个约束,这属于声明与定义不匹配的情况。

旧版本的编译器可能没有严格执行这一规则,所以能正常链接;但clang++ 18开始严格遵循C++标准,将requires约束作为符号名称的一部分,导致头文件声明生成的符号(无约束)与cpp定义生成的符号(带约束)不匹配,最终触发链接错误。

修复方法

将requires约束添加到头文件的模板声明中,确保声明与定义一致:

修改后的test.hpp:

#pragma once

#include <optional>
#include <string>
#include <type_traits>

template<class T>
    requires(!std::is_same_v<T, std::string>)
std::optional<T> myFunction(std::string arg);

这样修改后,clang++ 18就能生成匹配的符号,链接错误会消失。


内容的提问来源于stack exchange,提问作者Étienne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 19:13:19