【发布时间】:2019-06-18 11:27:57
【问题描述】:
背景
根据 C++ 标准,当使用默认模板参数前向声明模板类型时,它们中的每一个都只能出现在 one 声明中。例如:
// GOOD example
template <class T = void>
class Example; // forward-declaration
template <class T>
class Example {}; // definition
// GOOD example
template <class T>
class Example; // forward-declaration
template <class T = void>
class Example {}; // definition
// BAD example
template <class T = void>
class Example; // forward-declaration
template <class T = void> // ERROR: template parameter redefines default argument
class Example {}; // definition
问题
在我的代码中,我在不同的文件中有很多前向声明,因此将我的默认参数放在定义中是有意义的:
// foo.hpp, bar.hpp, baz.hpp, etc.
template <class T>
class Example;
// example.hpp
template <class T = void>
class Example {};
而且,正如预期的那样,它在任何地方都运行良好......除了叮当声!我把问题缩小到这个:
在clang中,如果类模板具有默认参数,但它们没有在该类的第一个前向声明中声明,并且在声明该类的实例时没有指定尖括号 em>,clang 忽略默认参数并引发错误“没有可行的构造函数或推导指南用于推导 ... 的模板参数”。
示例
// GOOD example
template <class T>
class Example;
template <class T = void>
class Example {};
int main() {
Example e; // error: no viable constructor or deduction guide for deduction of template arguments of 'Example'
}
- 将
= void移至前向声明可解决此问题,但对我来说不可行,因为我的前向声明位于不同的文件中,我不知道哪个会首先出现。 (这也是超级问题,因为我的默认值会在代码库深处的一些不起眼的文件中) - 将
Example e;更改为Example<> e;可以解决此问题,但对我来说不可行,因为我是一名图书馆开发人员,并且不希望我的所有用户在我的课后都输入<>。 - 添加带有一个前向声明的前向声明文件
example_fwd.hpp并包含它而不是每次都前向声明可以解决问题,但如果有更好的解决方案,我想避免这种情况。
问题
在这种情况下谁是对的:clang 还是其他编译器?这是编译器错误吗?我该如何规避这个问题(除了我上面描述的部分解决方案)? 我找到了#10147(以及相关的 stackoverflow 问题),但它是关于模板模板参数的,并且在一年前被标记为已修复。
编辑
这看起来像一个错误,现在在 LLVM bugtracker (#40488) 上报告。
【问题讨论】:
-
扣分指南能解决吗?看来at least in your example...
-
不确定 SO 是否是此错误报告的正确位置。 LLVM 支持可能更适合于此。
-
@SergeyA 但这是确认这是一个错误的理想场所,特别是因为 OP 不确定。
-
我不知道是谁在介绍演绎指南,但this 点在铿锵声中
标签: c++ templates clang default-arguments