gpt4 book ai didi

c++ - 避免在模板的前向声明中出现重复的 require 子句?

转载 作者:行者123 更新时间:2023-11-30 02:28:17 24 4
gpt4 key购买 nike

我正在一个新项目中使用 Concepts TS。我的问题与结构模板和我想要创建的关联概念之间的看似循环依赖有关。该概念的具体逻辑是检查该概念的类型参数是否是结构模板的特化。由于我希望该概念可在结构模板内部使用,因此我显然需要在结构模板之前定义该概念,但概念的逻辑也需要了解结构模板。我已经找到了一些可以编译的东西,方法是向前声明结构模板Vector,然后定义概念VectorSpecialization,最后定义 结构模板Vector。我的具体问题与我对结构模板使用 requires 子句有关;当我转发声明它时,编译器会给我一个错误,除非我复制完整的 requires 子句。 (参见下面的代码)。

我的具体问题是:有没有办法避免模板的前向声明和定义之间的 requires 子句完全重复?一种可能性是将 requires 子句的逻辑分解为一个公共(public)实体,声明和定义都可以委托(delegate)给该实体,我认为这将解决 DRY 原则;但我很好奇我是否可以在这里做出更高级别的结构决策,以避免在两个地方都需要 requires 子句,或者是否有更惯用的方法来使用概念我可以从中受益的类似用例。重申一下,我所说的用例是:编写一个将在模板中使用的概念,但该概念还需要了解模板。

// Forward declare the struct template so that the concept can refer to it
// Note the need to repeat the 'requires' clause. Can that repetition be
// be avoided?
template< typename T, size_t N > requires N > 1 struct Vector;

// compile-time overload set using template arg deduction to detect
// when the argument is a specialization of 'Vector'
template< typename NonVector >
constexpr bool IsVectorSpecialization( NonVector && ) {
return false;
}
template< typename T, size_t N >
constexpr bool IsVectorSpecialization( Vector<T, N> && ) {
return true;
}

// The concept, which uses the above overloaded constexpr function
template< typename VectorCandidate >
concept bool VectorSpecialization_CV
= IsVectorSpecialization( std::declval<VectorCandidate>() );

template< typename T, size_t N >
requires N > 1
struct Vector : std::array<T, N> {
// Some function templates with VectorSpecialization parameters, e.g.
// T dot( VectorSpecialization const &other ) const;
// ...
};

(注意:除了具体问题之外,我还欢迎讨论(当然是在评论中)有关与此问题和/或人们提供的解决方案有关的概念 TS 设计的各个方面,因为我使用 Concepts TS 的部分原因是想看看它在实践中的表现如何,看看在完全标准化之前委员会是否有任何有用的反馈。例如,“Concepts Lite”的设计是否有调整“这可以消除像这样重复 requires 子句的需要吗?)

最佳答案

受约束模板提供的保证之一是,每当命名模板专门化时,参数都必须满足约束。请参阅 P121R0 §14.3 [temp.names]/8:

When the template-name of a simple-template-id names a constrained non-function template or a constrained template template-parameter, but not a member template that is a member of an unknown specialization (14.7), and all template-arguments in the simple-template-id are non-dependent 14.6.2.4, the associated constraints of the constrained template shall be satisfied. (14.10.2).

在您的示例中,这意味着例如命名 Vector<int, 1> 格式不正确即使没有实例化它:

template< typename T, size_t N > requires N > 1 struct Vector;
using foo = Vector<int, 1>*;
// ill-formed: constraints not satisfied: '(N > 1)' evaluated to false

如果可以在没有关联约束的情况下声明模板,则无法强制执行该保证。关联的约束是声明的关键部分。

这在函数模板的上下文中更加明显,否则具有不同关联约束的相同函数模板声明声明重载。例如:

template<typename T>
requires true
bool foo(T) { return true; }

template<typename>
constexpr bool always_false = false;

template<typename T>
requires always_false<T>
bool foo(T) { return false; }

这是一个完全有效的程序,它声明了两个名为 foo 的重载函数模板。 ,其中第二个永远不会被重载决策选择。同样,相关的约束是声明的一个显着特征。有必要在每个声明中重复关联的约束,就像重复模板实体的名称或参数的数量和种类一样。

概念是语言提供的管理这种重复的机制:我们为它们提供方便的名称,而不是一遍又一遍地重复巨大的约束表达式。 N > 1还不足以需要一个命名概念来节省击键次数,但是 providing a single point of definition for the notion is clearly worthwhile :

template< size_t N > concept bool VectorLength = N > 1;
template< typename T, VectorLength N > struct Vector;

template< typename >
constexpr bool IsVectorSpecialization = false;
template< typename T, size_t >
constexpr bool IsVectorSpecialization<Vector<T, N>> = true;

template< typename VC >
concept bool VectorSpecialization = IsVectorSpecialization<VC>;

template< typename T, VectorLength N >
struct Vector : std::array<T, N> {
T dot( VectorSpecialization const& );
};

确实没有其他选择来定义这种结构。概念无法前向声明的事实有时很烦人,但我发现已分解为避免无法表达的循环依赖所需的线性结构的设计非常容易理解。

关于c++ - 避免在模板的前向声明中出现重复的 require 子句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40925053/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com