C++20概念中STL流的意外替代是如何发生的?

huangapple go评论62阅读模式
英文:

Unexpected substitution with STL streams of C++20 concept. How did it happen?

问题

以下是您要翻译的内容:

There is an example compiled by LLVM 15.0.0, about the C++20 concepts. FYI. all of the code could be found here https://godbolt.org/z/zearGEe5K.

#include <iostream>
#include <concepts>

template <typename T>
struct RawStreamTraits
{
    using Ch = typename T::char_type;
};

template <typename T>
using RawStreamCharType = typename RawStreamTraits<T>::Ch;

template <typename _StreamT>
concept SameAsStdBasicInputStream = std::same_as<_StreamT, std::basic_istream<RawStreamCharType<_StreamT>>;

template <typename _StreamT>
concept DerivedFromStdInputStream = std::derived_from<_StreamT, std::basic_istream<RawStreamCharType<_StreamT>>;

template <typename _StreamT>
concept RawInputStream = requires {
    SameAsStdBasicInputStream<_StreamT> || DerivedFromStdInputStream<_StreamT>;
};

static_assert(RawInputStream<std::istream>); // 1
static_assert(RawInputStream<std::ostream>); // 2
static_assert(SameAsStdBasicInputStream<std::istream>);  // 3
static_assert(DerivedFromStdInputStream<std::istream>);  // 4
static_assert(SameAsStdBasicInputStream<std::ostream>);  // 5 ERR!
static_assert(DerivedFromStdInputStream<std::ostream>);  // 6 ERR!

I cannot understand the result. In my opinion, the 1st one and the 3rd one should be evaluated to true, the 4th one is uncertain, and others should be false.

As the 5th one and 6th one shows, std::ostream does not satisfy any sub-concept of RawInputStream, but RawInputStream<std::ostream> is true. That's the most confusing result.

Of course, std::istream is not derived from itself, or std::basic_stream<char>. so the 4th one should be false, am I right?

And, the result would not change, if you replace the std::same_as with std::is_same_v, or replace the std::derived_from with std::is_base_of, and exchange the base type and derived type.

Could anyone help me on this question? I have no idea about this result...

英文:

There is an example compiled by LLVM 15.0.0, about the C++20 concepts. FYI. all of the code could be found here https://godbolt.org/z/zearGEe5K.

#include &lt;iostream&gt;
#include &lt;concepts&gt;

template &lt;typename T&gt;
struct RawStreamTraits
{
    using Ch = typename T::char_type;
};

template &lt;typename T&gt;
using RawStreamCharType = typename RawStreamTraits&lt;T&gt;::Ch;

template &lt;typename _StreamT&gt;
concept SameAsStdBasicInputStream = std::same_as&lt;_StreamT, std::basic_istream&lt;RawStreamCharType&lt;_StreamT&gt;&gt;&gt;;

template &lt;typename _StreamT&gt;
concept DerivedFromStdInputStream = std::derived_from&lt;_StreamT, std::basic_istream&lt;RawStreamCharType&lt;_StreamT&gt;&gt;&gt;;

template &lt;typename _StreamT&gt;
concept RawInputStream = requires {
    SameAsStdBasicInputStream&lt;_StreamT&gt; || DerivedFromStdInputStream&lt;_StreamT&gt;;
};

static_assert(RawInputStream&lt;std::istream&gt;); // 1
static_assert(RawInputStream&lt;std::ostream&gt;); // 2
static_assert(SameAsStdBasicInputStream&lt;std::istream&gt;);  // 3
static_assert(DerivedFromStdInputStream&lt;std::istream&gt;);  // 4
static_assert(SameAsStdBasicInputStream&lt;std::ostream&gt;);  // 5 ERR!
static_assert(DerivedFromStdInputStream&lt;std::ostream&gt;);  // 6 ERR!

I cannot understand the result. In my opinion, the 1st one and the 3rd one should be evaluated to true, the 4th one is uncertain,and others should be false.

As the 5th one and 6th one shows, std::ostream does not satisfy any sub-concept of RawInputStream, but RawInputStream&lt;std::ostream&gt; is true. That's the most confusing result.

Of course, std::istream is not derived from itself, or std::basic_stream&lt;char&gt;. so the 4th one should be false, am I right?

And, the result would not change, if you replace the std::same_as with std::is_same_v, or replace the std::derived_from with std::is_base_of, and exchange the base type and derived type.

Could anyone help me on this question? I have no idea about this result...

答案1

得分: 1

对于你定义的RawInputStream概念:

template <typename _StreamT>
concept RawInputStream = requires {
  SameAsStdBasicInputStream<_StreamT> || DerivedFromStdInputStream<_StreamT>;
};

它将仅仅检查requires子句中的表达式的有效性,而不会对其进行评估。

你可以使用额外的requires来评估值并将其约束为true

template <typename _StreamT>
concept RawInputStream = requires {
  requires SameAsStdBasicInputStream<_StreamT> || DerivedFromStdInputStream<_StreamT>;
};

或者只需:

template <typename _StreamT>
concept RawInputStream = 
   SameAsStdBasicInputStream<_StreamT> || DerivedFromStdInputStream<_StreamT>;

当然,std::istream并不是派生于它自己,或者std::basic_stream<char>。所以第四个应该是false,我对吗?

std::derived_from在两个模板参数是相同类类型时返回true,这与std::is_base_of_v一致,这也是为什么DerivedFromStdInputStream<std::istream>返回true的原因。

此外,你可以直接在概念中写入提取char_type而不是使用额外的RawStreamTraits,像这样:

template <typename _StreamT>
concept SameAsStdBasicInputStream = 
  std::same_as<_StreamT, std::basic_istream<typename _StreamT::char_type>>;
英文:

For the RawInputStream concept you defined

template &lt;typename _StreamT&gt;
concept RawInputStream = requires {
  SameAsStdBasicInputStream&lt;_StreamT&gt; || DerivedFromStdInputStream&lt;_StreamT&gt;;
};

It will only check the validity of the expression in the requires-clause, without evaluating it.

You can use additional requires to evaluate the value and constrain it to be true:

template &lt;typename _StreamT&gt;
concept RawInputStream = requires {
  requires SameAsStdBasicInputStream&lt;_StreamT&gt; || DerivedFromStdInputStream&lt;_StreamT&gt;;
};

or just

template &lt;typename _StreamT&gt;
concept RawInputStream = 
   SameAsStdBasicInputStream&lt;_StreamT&gt; || DerivedFromStdInputStream&lt;_StreamT&gt;;

> Of course, std::istream is not derived from itself, or
> std::basic_stream&lt;char&gt;. so the 4th one should be false, am I right?

std::derived_from is true when the two template parameters are of the same class type, which is consistent with std::is_base_of_v, which is why DerivedFromStdInputStream&lt;std::istream&gt; is true.

Also, instead of using extra RawStreamTraits to extract the char_type, you can write it directly in the concept like

template &lt;typename _StreamT&gt;
concept SameAsStdBasicInputStream = 
  std::same_as&lt;_StreamT, std::basic_istream&lt;typename _StreamT::char_type&gt;&gt;;

huangapple
  • 本文由 发表于 2023年2月14日 21:13:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75448373.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定