Disable non-templated methods with concepts

落花浮王杯 提交于 2021-02-16 17:58:25

问题


Is there a syntax to constraint a non-templated method? All the syntaxes I've tried on godbolt with clang concepts branch and gcc fail to compile:

// 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() {}
};

The trick to make it compile is the same trick you needed to do with SFINAE, make the methods template, even though they really are not templates. And funny enough, the constraint doesn't seem to need the method template, it can work fine on the class template alone, so I really hope there is a way to apply the constraints with concepts without having to resort to the old hacks:

// 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() {}
};

Real life example:

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>;

回答1:


To support the other answer on this, here is the normative wording about this, from the latest standard draft:

[dcl.decl]

1 A declarator declares a single variable, function, or type, within a declaration. The init-declarator-list appearing in a declaration is a comma-separated sequence of declarators, each of which can have an initializer.

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

4 The optional requires-clause ([temp]) in an init-declarator or member-declarator shall not be present when the declarator does not declare a function ([dcl.fct]). When present after a declarator, the requires-clause is called the trailing requires-clause. The trailing requires-clause introduces the constraint-expression that results from interpreting its constraint-logical-or-expression as a constraint-expression. [ Example:

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

— end example ]

As those two paragraphs specify, a trailing requires clause can appear at the end of function declarators. Its meaning is to constrain the function by the constant expression it accepts as an argument (which includes concepts).




回答2:


Yes, there is!! The requires clause can appear as the last element of a function declarator, in which case it allows to constraint non-templated methods (or free functions for that matter):

// 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>
    {
        // ...
    }
};

This answer is empirical, based on testing on current implementations of concepts. Godbolt test. Storry Tellers's answer gives standard quotes confirming this behavior.




回答3:


There was a change regarding this recently. See https://github.com/cplusplus/nbballot/issues/374

It states:

How constraints work with non-templated functions is still under heavy construction during this late stage in the process. While we have provided various comments that build in a direction where supporting such constructs (including ordering between multiple constrained functions based on their constraints) would become possible, we acknowledge that WG 21 might not find a solution with consensus in time for the DIS. We ask WG 21 to evaluate the risk of shipping the feature in such a state and consider removing the ability to declare such functions.

Does EWG want to consider this for C++20?

 |  F |  A |
 |----|----|
 | 16 |  0 |

Motion passes. Hubert to coordinate with CWG.

Emphasis mine.

So it appears that constrained non-templated functions were removed from C++20 as of right now.



来源:https://stackoverflow.com/questions/58381851/disable-non-templated-methods-with-concepts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!