C++ 使用可变概念模板时发生gcc内部错误

C++ 使用可变概念模板时发生gcc内部错误,c++,gcc,C++,Gcc,我最近在gcc中使用了concepts功能,在类的构造函数或成员函数中使用可变概念模板时偶然发现了这个错误: template<typename From, typename To> concept bool ConvertibleNoNarrow = requires(From f, To t) { t = { f }; }; class Foo { public: template<ConvertibleNoNarrow<double>...

我最近在
gcc
中使用了concepts功能,在类的构造函数或成员函数中使用可变概念模板时偶然发现了这个错误:

template<typename From, typename To>
concept bool ConvertibleNoNarrow = requires(From f, To t) {
    t = { f };
};

class Foo
{
public:
    template<ConvertibleNoNarrow<double>... Args>
    Foo(Args&&... args) { /*...*/ }
};
如果在全局函数中使用相同的签名,则一切都会按预期工作:

/* works */    
template<ConvertibleNoNarrow<double>... Args>
void Test(Args&&... args) { }
这是gcc()中的一个bug

不过,您可以通过在
requires
子句中添加约束来解决此问题。因此,我们检查每个类型的概念,并相应地返回
std::true\u type
std::false\u type
。通过这样做,我们可以使用
std::conjunction_v
和参数包扩展来独立约束每种类型

class Foo
{
public:
    template<typename... Args>
        requires std::conjunction_v<std::conditional_t
            < ConvertibleNoNarrow<Args, double>
            , std::true_type
            , std::false_type
            >...>
    Foo(Args&&... args) { /*...*/ }
};
class-Foo
{
公众:
模板
需要std::conjunction\u v…>
Foo(Args&&…Args){/*…*/}
};

与@nyronium的答案类似,但更简单一点,可以在requires子句中使用折叠表达式

class Foo
{
public:
    template<typename... Args>
        requires (ConvertibleNoNarrow<Args, double> && ...)
    Foo(Args&&... args) { /*...*/ }
};
class-Foo
{
公众:
模板
需要(可转换狭窄和…)
Foo(Args&&…Args){/*…*/}
};
我在GCC 7.3.0上测试了等效项。

似乎是
class Foo
{
public:
    template<typename... Args>
        requires std::conjunction_v<std::conditional_t
            < ConvertibleNoNarrow<Args, double>
            , std::true_type
            , std::false_type
            >...>
    Foo(Args&&... args) { /*...*/ }
};
class Foo
{
public:
    template<typename... Args>
        requires (ConvertibleNoNarrow<Args, double> && ...)
    Foo(Args&&... args) { /*...*/ }
};