带模板化非类型参数的类模板分离实现编译失败求助
问题背景
你实现了带推导指引的FixedString模板,以及以未指定大小FixedString为模板参数的Foo类,将类方法分离到实现文件时出现编译错误,希望了解能否在不硬编码字符串大小的情况下分离实现,是否必须用单头文件方案。
相关代码实现
FixedString.hpp
// FixedString.hpp template <size_t N> struct FixedString { char chars[N+1] = {}; constexpr FixedString (const char (&str)[N+1]) { std::copy_n(str, N+1, chars); } }; template <size_t N> FixedString (const char (&str)[N]) -> FixedString<N-1>;
Foo.hpp
// Foo.hpp #include "FixedString.hpp" template <FixedString TName> class Foo { public: Foo (); }; #include "Foo.impl.hpp"
OtherFile.hpp
// OtherFile.hpp using Bar_t = Foo<"bar">;
编译错误信息
- class template argument deduction failed
- no matching function for call to 'FixedString(FixedString<...auto...>)'
- conflicting declaration of template 'template<FixedString<...auto...> TName> int Foo()'
核心问题
能否在不硬编码固定字符串大小的情况下分离实现?若要自动推导字符串大小,是否只能采用单头文件方案?
解决方案
可以在不硬编码字符串大小的情况下分离实现,问题根源在于模板参数的声明与实现不匹配。编译器处理非类型模板参数的简写形式时,无法在分离文件中正确推导关联的大小参数,导致声明和实现冲突。以下两种方案均可解决:
方案一:显式关联大小参数
修改Foo的模板参数声明,显式带上FixedString的大小模板参数N,让编译器能明确匹配声明与实现:
修改后的Foo.hpp
// Foo.hpp #include "FixedString.hpp" // 显式声明模板参数为FixedString<N>,N为自动推导的字符串大小 template <size_t N, FixedString<N> TName> class Foo { public: Foo(); }; #include "Foo.impl.hpp"
修改后的Foo.impl.hpp
// Foo.impl.hpp template <size_t N, FixedString<N> TName> Foo<N, TName>::Foo() { // 构造函数具体实现 }
方案二:利用C++20 auto非类型模板参数
如果编译器支持C++20及以上标准,可以直接用auto匹配模板参数,让编译器自动推导FixedString的具体类型(包括大小):
修改后的Foo.impl.hpp
// Foo.impl.hpp template <FixedString auto TName> Foo<TName>::Foo() { // 构造函数具体实现 }
两种方案都不需要局限于单头文件结构,既保留了字符串大小的自动推导能力,又支持类方法的分离实现。
内容的提问来源于stack exchange,提问作者Nicholas Bonjour
相关产品推荐
相关产品推荐

