C++使用默认模板参数键入别名和转发声明

C++ type alias and forward declaration with default template parameter

本文关键字:别名 转发 声明 参数 默认 C++      更新时间:2023-10-16

我想使用来自第三方仅标头库的span类实现,但为其使用不同的命名空间。我几乎做的是创建新的span.hpp代理标头,其中包括库并将其引入新的命名空间。

现在,当尝试包含该代理标头时,我的整个翻译单元编译中断,就好像它在语法上不正确一样(很多很多随机错误(

(编辑:我发现了有问题的错误并将其粘贴在最底部(:

namespace new_namespace
{
template <std::size_t Value = ::old_namespace::dynamic_extent>
class span;
template <std::size_t Value>
using span = ::old_namespace::span<Value>;
}

在简单地编写代码后,它工作得很好:

namespace new_namespace
{
template <std::size_t Value = ::old_namespace::dynamic_extent>
using span = ::old_namespace::span<Value>;
}

我的问题是 - 假设我真的,真的很想将默认模板参数和类型别名分开进行转发声明。在这种情况下,我如何实现此目的?

编辑:

有问题的错误是:

/span.hpp:12:46: error: conflicting declaration of template 'template<long unsigned int Value> using span = old_namespace::span<T>'
using span = ::old_namespace::span<Value>;
^
/span.hpp:9:7: note: previous declaration 'template<long unsigned int Value> class new_namespace::span'
class span;

所以两者都被视为声明?这里到底发生了什么,它们是如何冲突的?

还有一件事,old_namespace::span 的定义为模板参数 Value 提供了一个默认值,形式为:

namespace old_namespace
{
template <typename Value = dynamic_extent> // Default parameter in forward declaration
class span;
template <typename Value> // No default parameter here
class span
{
...
}
}

为什么using别名不从原始类中查找默认模板参数?如果我尝试省略默认参数,例如简单地编写:

namespace new_namespace
{
template <std::size_t Value> // no default parameter provided
using span = ::old_namespace::span<Value>;
}

尝试在没有任何模板参数的情况下实例化 span 时出错

提前感谢您的帮助。 :)

干杯

根据规范,这不能按照您希望的方式工作(使用前向声明(。前向声明不能由using稍后定义。来自 C++11 关于使用声明的规范:

由于using-声明是声明,因此对同一声明区域中同名声明的限制 (3.3( 也适用于using 声明。 -- [namespace.udecl] §7.3.3 ¶13

我认为问题在于类前瞻声明和使用声明是......很明显,这两个声明

// Declares span as a template class.
template <std::size_t Value = ::old_namespace::dynamic_extent>
class span;
// Attempts to redeclare span as something else -- this is invalid.
template <std::size_t Value>
using span = ::old_namespace::span<Value>;

在你给出的示例中,它仅适用于class,你没有两个声明 - 你有一个前向声明和一个定义(如果尚未声明,则意味着声明(:

// Forward declaration.
template <typename Value = dynamic_extent>
class span;
// Definition, which agrees with the forward declaration -- no error.
template <typename Value>
class span
{
...
}

问题的症结相当简单:你不能声明相同的名称意味着两件不同的事情:

给定单个声明区域中的一组声明,每个声明指定相同的非限定名称,

  • 它们应都指代同一个实体... -- [basic.scope.declarative] §3.3.1 ¶4

当您尝试以这种方式一起使用classusing时,它们不会引用同一个实体。因此,这是不允许的。


此问题的一个可能的解决方案是在别名中使用模板参数包:

template <std::size_t... T>
using span = ::old_namespace::span<T...>;

现在span<>::old_namespace::span<>的别名,任何默认值都将根据需要使用。