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

bol*_*lov 4 c++ c++-concepts c++20

有没有语法可以约束非模板化方法?我在使用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() {}
};
Run Code Online (Sandbox Code Playgroud)

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

// 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() {}
};
Run Code Online (Sandbox Code Playgroud)

现实生活中的例子:

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>;
Run Code Online (Sandbox Code Playgroud)

Sto*_*ica 5

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

[dcl.decl]

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

初始化声明者列表:
    初始化声明符
    初始化声明者列表
初始化声明符:
    声明器初始化器opt
    声明符要求子句

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
Run Code Online (Sandbox Code Playgroud)

—结束示例]

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


bol*_*lov 4

就在这里!!require 子句可以作为函数声明符的最后一个元素出现,在这种情况下,它允许约束非模板化方法(或与此相关的自由函数):

// 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>
    {
        // ...
    }
};
Run Code Online (Sandbox Code Playgroud)

这个答案是经验性的,基于对当前概念实现的测试。上帝螺栓测试讲故事的人的回答给出了证实这种行为的标准引述。