小编md1*_*357的帖子

为什么使用推导类类型的占位符聚合初始化非类型模板参数无法编译?

考虑以下代码:

struct Base_string { char data[1 << 5]; };

template<typename Base>
struct Derived: Base { };

Derived(char const*) -> Derived<Base_string>;

template<Derived>
struct S { };

S<{"Test"}> s; // Error
Run Code Online (Sandbox Code Playgroud)

最后一行被S实例化,无法编译。我希望它能起作用,因为[temp.arg.nontype#1]指出:

如果模板参数的类型 T 包含 [...] 推导类类型的占位符,则参数的类型是为发明声明中的变量 x 推导的类型T x = template-argument;

就我而言,这个发明的声明看起来像这样:Derived x = {"Test"};,并且实际上在程序中声明这样的变量不会产生错误 - 类型被正确推导。
另外,我认为问题不在于聚合初始化语法本身 - 将模板的定义更改S为:

template<Base_string>
struct S { };
Run Code Online (Sandbox Code Playgroud)

并以相同的方式实例化它 ( S<{"Test"}> s;) 不会产生错误。

我知道我可以简单地显式指定类型,如下所示:S<Derived{"Test"}> s;,但我不是在寻找解决方法,我想了解为什么推导在这里失败。

c++ metaprogramming language-lawyer c++20

7
推荐指数
0
解决办法
121
查看次数

当概念变为可变参数时,为什么这段代码不再编译?

让我们定义以下模板:

template<typename> concept C_one = true;
template<typename...> concept C_many = true;

template<bool> struct S { };
Run Code Online (Sandbox Code Playgroud)

现在,让我们尝试使用它们。
这一行编译:

template<typename T = S<C_one<int>>> void f() { }
Run Code Online (Sandbox Code Playgroud)

而这个则没有:

template<typename T = S<C_many<int>>> void f() { }
Run Code Online (Sandbox Code Playgroud)

我收到的错误是:

error: type/value mismatch at argument 1 in template parameter list for 'template<bool <anonymous> > struct S'
Run Code Online (Sandbox Code Playgroud)

我注意到用C_many<int>括号括起来可以解决这个问题,但是这种看似不一致的语法的原因是什么?我认为错误消息也没有多大帮助。
另外,我知道这可能是一个非常人为的示例,因为我尝试创建一个最小的可重现示例。

c++ syntax templates language-lawyer c++20

6
推荐指数
0
解决办法
86
查看次数

组合正则表达式和范围会导致内存问题

regex我想构建一个关于in的所有子匹配的视图text。以下是定义此类视图的两种方法:

    char const text[] = "The IP addresses are: 192.168.0.25 and 127.0.0.1";
    std::regex regex{R"((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}))"};

    auto sub_matches_view = 
        std::ranges::subrange(
            std::cregex_iterator{std::ranges::begin(text), std::ranges::end(text), regex},
            std::cregex_iterator{}
        ) |
        std::views::join;

    auto sub_matches_sv_view = 
        std::ranges::subrange(
            std::cregex_iterator{std::ranges::begin(text), std::ranges::end(text), regex},
            std::cregex_iterator{}
        ) |
        std::views::join |
        std::views::transform([](std::csub_match const& sub_match) -> std::string_view { return {sub_match.first, sub_match.second}; });
Run Code Online (Sandbox Code Playgroud)
  • sub_matches_view的值类型是std::csub_match. 它是通过首先构造对象视图std::cmatch(通过正则表达式迭代器)来创建的,并且由于每个对象std::cmatch都是一系列std::csub_match对象,因此它被展平为std::views::join.
  • sub_matches_sv_view的值类型是std::string_view. 它与 相同,只是它也包装了a 中sub_matches_view的每个元素。sub_matches_viewstd::string_view

以下是上述范围的使用示例:

for(auto const& sub_match : sub_matches_view) …
Run Code Online (Sandbox Code Playgroud)

c++ regex memory c++20

6
推荐指数
1
解决办法
312
查看次数

尽管标准库类型嵌套在实现定义的命名空间中,但为什么可以在“std”内部访问标准库类型?

我正在浏览 GCC 11.2 标头的实现<optional>(可以在此处找到),我注意到一些我很难理解的东西。这是标题(希望)只留下了重要的部分:

#ifndef _GLIBCXX_OPTIONAL
#define _GLIBCXX_OPTIONAL 1

#pragma GCC system_header

#if __cplusplus >= 201703L

/* Includes of various internal and library headers */

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

#if __cplusplus == 201703L
# define __cpp_lib_optional 201606L
#else
# define __cpp_lib_optional 202106L
#endif

  /* Implementation */

  template<typename _Tp>
  class optional;

  /* Implementation */

  template<typename _Tp>
  class optional: /* Implementation */
  { /* Implementation */ };

  /* Implementation */


_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std

#endif // …
Run Code Online (Sandbox Code Playgroud)

c++ namespaces std language-lawyer c++20

2
推荐指数
1
解决办法
328
查看次数