【问题标题】:C++ concept member check type ambiquity with referenceC++ 概念成员检查类型歧义与参考
【发布时间】:2021-05-03 12:59:12
【问题描述】:

我正在学习 C++ 概念,但遇到了一个令人讨厌的问题:

我不知道如何区分成员变量是int 类型的变量和成员变量是int&

原因是我正在使用的检查使用 instance.member 语法,并且在 C++ 中返回引用。

完整示例:

#include <iostream>
#include <concepts>

template<typename T>
void print(T t) {
    std::cout << "generic" << std::endl;
}

template<typename T>
requires requires(T t){
    {t.val} -> std::same_as<int&>;
}
void print(T t) {
    std::cout << "special" << std::endl;
}

struct S1{
    int bla;
};

struct S2{
   int val = 47;
};
int x = 47;
struct S3{
    int& val=x;
};

int main()
{
    print(4.7);
    print(S1{});
    print(S2{});
    print(S3{});
}

我希望print(S3{}) 将由通用案例处理,而不是特殊案例。 请注意,将我的 requires 内容更改为:

 {t.val} -> std::same_as<int>;

使S2 与模板不匹配,因此不起作用(就像我说的那样,我认为 C++ 中的成员访问返回一个引用)。

有没有办法解决这个问题?

【问题讨论】:

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


    【解决方案1】:

    这里的问题是表达式概念检查在检查中使用decltype((e)) 而不是decltype(e)(额外的括号很重要)。

    因为t.valint 类型的左值(表达式永远没有引用类型),所以decltype((t.val)) 无论如何都是int&amp;,正如您所发现的。

    相反,您需要显式使用单括号语法:

    template <typename T>
    requires requires (T t) {
        requires std::same_as<decltype(t.val), int&>;
    }
    void print(T t) {
        std::cout << "special" << std::endl;
    }
    

    或者

    template <typename T>
    requires std::same_as<decltype(T::val), int&>
    

    【讨论】:

      【解决方案2】:

      解决办法是:

      template <typename T>
      requires requires(T t)
      {
          requires std::is_same_v<decltype(t.val), int>; // or `int &` for references
      }
      void print(T t)
      

      Clang 有一个错误导致 {T::val} -&gt; std::same_as&lt;int&gt; 也能正常工作,即使 lhs 的类型是 said to be,就像由 decltype((...)) 确定的一样,它应该在此处返回 int &amp;


      请注意,“C++ 中的成员访问返回引用” 为假。不可能,因为expressions can't have reference types。当你编写一个具有引用返回类型的函数时,调用它会产生一个非引用类型的左值。

      decltype 将根据值类别为表达式类型添加引用性(&amp; 用于左值,&amp;&amp; 用于 xvalues,prvalues 没有)。这就是为什么人们经常认为表达式可以有引用类型。

      它还对 variables 有一个特殊规则(与一般表达式相反),这会导致它返回所写的变量类型,而忽略 expression 类型和值类别。显然,t.val 为此目的算作一个变量。

      【讨论】:

      • 看起来 clang 13.0.0 已经修复了这个错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-28
      • 2021-09-15
      相关资源
      最近更新 更多