【问题标题】:Why can't the .size() of an array passed to a function as a constant reference be used as a template parameter?为什么不能将作为常量引用传递给函数的数组的 .size() 用作模板参数?
【发布时间】:2021-05-01 21:12:18
【问题描述】:

我似乎无法弄清楚为什么以下代码不起作用:

#include <array>

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(const std::array<int, s>& arr) {
    a<arr.size()>(); // error: no matching function for call to 'a'
}


int main() {
    const std::array<int, 2> arr {{0, 0}};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}

GCC 失败并显示以下内容:

test.cpp: In instantiation of ‘void b(const std::array<int, s>&) [with long unsigned int s = 2]’:
test.cpp:13:22:   required from here
test.cpp:6:18: error: no matching function for call to ‘a<(& arr)->std::array<int, 2>::size()>()’
    6 |     a<arr.size()>(); // Doesn't
      |     ~~~~~~~~~~~~~^~
test.cpp:3:37: note: candidate: ‘template<long unsigned int s> void a()’
    3 | template <long unsigned int s> void a() {}
      |                                     ^
test.cpp:3:37: note:   template argument deduction/substitution failed:
test.cpp:6:18: error: ‘arr’ is not a constant expression
    6 |     a<arr.size()>(); // Doesn't
      |     ~~~~~~~~~~~~~^~
test.cpp:6:15: note: in template argument for type ‘long unsigned int’
    6 |     a<arr.size()>(); // Doesn't
      |       ~~~~~~~~^~

我认为‘arr’ is not a constant expression 部分是最相关的,但我不明白为什么同一行在main() 中有效(那里是一个常量表达式吗?),以及为什么将arr 作为const 传递副本(而不是参考)也可以解决问题。

PS:我知道我可以使用a&lt;s&gt;();,但我只是想弄清楚这个错误的含义。

【问题讨论】:

  • 函数参数不能用作常量表达式。
  • @cigien 如果我将 b 的签名更改为void b(const std::array&lt;int, s&gt; arr)(通过副本),则没有错误。那不是使用函数参数作为常量表达式吗?
  • 嗯,那不应该编译。某处可能有一个正确的欺骗,但我使用的那个不是,所以我重新打开了。
  • 这是一个合理的target。看来 std::array 通过 value 传递给函数可以用作常量表达式,但如果它是通过 reference 传递的,则不能。

标签: c++ templates const-reference


【解决方案1】:
  1. 也许在 C++2X 中,它可以与 consteval 函数一起使用。

  2. 对于非参考参数有效 https://godbolt.org/z/Wx9va54z5。 我认为无论如何通过值传递std::array 的内置函数是可以的。 (这适用于 GCC 和 clang。)

#include <array>

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(std::array<int, s> arr) {
    a<arr.size()>(); // ok
}

int main() {
    const std::array<int, 2> arr = {};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}
  1. 要回答@acumandr 评论中的问题,是的,std::array 中的 staticconstexpr size() 成员函数可以工作(!),即使对于 const&amp; 参数也是如此。 https://godbolt.org/z/anP1e9qEr

更正:这仅适用于 GCC,在 clang 中不起作用 https://godbolt.org/z/65d5G9Yfo,谢谢 @IlCapitano

#include <array>

template<class T, std::size_t D>
struct MyArray{
    static constexpr std::size_t size(){return D;}
};

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(MyArray<int, s> const& arr) {
    a<arr.size()>(); // ok
}

int main() {
    const MyArray<int, 2> arr = {};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}

这更加令人费解,为什么 std::array 没有静态(和 constexpr)size 成员。

2.5) 更正:这仅适用于 GCC,在 clang 中不起作用 https://godbolt.org/z/65d5G9Yfo,感谢 @IlCapitano

在clang中,静态函数起作用但不传递实例,这违背了目的:

https://godbolt.org/z/En13aEWPz

#include <array>

template<class T, std::size_t D>
struct MyArray{
    static constexpr std::size_t size(){return D;}
};

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(MyArray<int, s> const& arr) {
    a<std::decay_t<decltype(arr)>::size()>(); // error: no matching function for call to 'a'
}

int main() {
    const MyArray<int, 2> arr = {};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}
  1. 使用std::tuple_size&lt;decltype(...)&gt;(或s本身)是一个很好的解决方法https://godbolt.org/z/K9xxKa1Px
#include <array>

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(std::array<int, s> arr) {
    a<std::tuple_size<decltype(arr)>::value /*or just s*/>(); // ok
}

int main() {
    const std::array<int, 2> arr = {};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}

【讨论】:

  • 你的第二个例子doesn't work with Clang
  • @IlCapitano,很好,谢谢。我添加了一个更正。
  • 我认为@cigien 链接的帖子按照我的理解回答了这个问题(我什至没有考虑过尺寸是多少),但我喜欢这一点! (我希望我能投票!)
猜你喜欢
  • 2019-11-16
  • 1970-01-01
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 2011-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多