禁用带有概念的非模板化方法

时间:2019-10-14 17:55:10

标签: c++ c++20 c++-concepts

是否有一种语法可以约束非模板方法?我在使用clang concept branch和gcc的Godbolt上尝试过的所有语法都无法编译:

// these examples do not compile

template <bool B>
struct X
{
    requires B
    void foo() {}
};

template <class T>
struct Y
{
    requires (std::is_trivially_copyable_v<T>)
    auto foo() {}
};

使其编译的诀窍与使用SFINAE一样,使方法成为模板,即使它们实际上不是模板也是如此。有趣的是,约束似乎不需要方法模板,它可以单独在类模板上正常工作,所以我真的希望有一种方法可以将约束应用于概念而不必求助于旧的技巧: / p>

// old hacks

template <bool B>
struct X
{
    template <bool = B>
    requires B
    auto foo() {}
};

template <class T>
struct Y
{
    template <class = T>
    requires std::is_trivially_copyable_v<T>
    auto foo() {}
};

现实生活中的例子:

template <class T, bool Copyable_buf = false>
struct Buffer
{
    /* ... */

    requires Copyable_buf
    Buffer(const Buffer& other)  {}

    /* ... */
};

template <class T>
using Copyable_buffer = Buffer<T, true>;

3 个答案:

答案 0 :(得分:5)

为支持对此的其他回答,以下是最新标准草案中关于此的规范性措辞:

  

[dcl.decl]

     

1声明器在声明中声明单个变量,函数或类型。出现在声明中的init-declarator-list是逗号分隔的一系列声明符,每个声明符可以具有一个初始化程序。

init-declarator-list:
    init-declarator
    init-declarator-list , init-declarator
init-declarator:
    declarator initializeropt
    declarator requires-clause
     

4当声明者未声明函数([dcl.fct])时,init声明者或成员声明者中的可选要求子句([temp])将不存在。当在声明器之后出现时,需求子句称为尾随需求子句。尾随的需求子句引入了约束表达式,该约束表达式是通过将其约束逻辑或表达式解释为约束表达式而得到的。 [示例:

void f1(int a) requires true;               // OK
auto f2(int a) -> bool requires true;       // OK
auto f3(int a) requires true -> bool;       // error: requires-clause precedes trailing-return-type
void (*pf)() requires true;                 // error: constraint on a variable
void g(int (*)() requires true);            // error: constraint on a parameter-declaration

auto* p = new void(*)(char) requires true;  // error: not a function declaration
     

—结束示例]

正如这两段所指定的那样,尾随的require子句可以出现在函数声明符的末尾。其含义是通过接受作为参数的常量表达式(包括概念)来约束函数。

答案 1 :(得分:4)

是的,有!! The requires clause可以作为函数声明符的最后一个元素出现,在这种情况下,它可以约束非模板方法(或与此相关的自由函数):

// This works as expected! Yey!!

template <class T, bool Copyable_buf = false>
struct Buffer
{
    Buffer(const Buffer& other) requires Copyable_buf
    {
        // ...
    }
};

template <bool B>
struct X
{
    auto foo() requires B
    {
        // ...
    }
};

template <class T>
struct Y
{
    auto foo() requires std::is_trivially_copyable_v<T>
    {
        // ...
    }
};

此答案是经验性的,基于对当前概念实现的测试。 Godbolt testStorry Tellers's answer给出标准报价来确认此行为。

答案 2 :(得分:4)

最近有一个变化。参见https://github.com/cplusplus/nbballot/issues/374

它说明:

  

在此过程的后期,约束如何与非模板功能一起使用尚处于繁琐的工作中。尽管我们提供了各种评论,这些评论的方向可能会支持此类构造(包括基于其约束在多个受约束函数之间进行排序),但我们承认,第21工作组可能无法及时找到DIS的共识解决方案。 我们要求21工作组评估在这种状态下发布功能的风险,并考虑取消声明此类功能的能力。

     

EWG是否要针对C ++ 20考虑这一点?

do
     

动作通过。休伯特与CWG进行协调。

强调我的。

因此看来,截至目前,已从C ++ 20中删除了受约束的非模板函数。