【发布时间】:2014-10-17 09:24:01
【问题描述】:
在尝试使用 constexpr 函数和模板(以及非类型模板参数)时,我偶然发现了一个现象,我无法理解是哪个规则使其生效。
所以我的问题本质上是“为什么会发生这种情况”,根据关于 constexpr-s 的规则。 "this" 如下。
在其中一个 constexpr 函数中,如果直接使用参数,则在编译时计算中使用该参数没有问题。 (示例第 2 行)
当相同的参数被用作另一个 constexpr 函数的参数时,编译器会抱怨这个表达式(参数 id)不是 constexpr。 (示例第 3 行)
简而言之:
template <typename T> constexpr std::size size (T obj) { return obj.size(); }
template <typename T> constexpr auto sz1 (T obj) { return std::make_index_sequence< obj.size() > { }.size(); } // OK ...
template <typename T> constexpr auto sz2 (T obj) { return std::make_index_sequence< size(obj) > { }.size(); } // ERROR
// "obj" is [suddenly] not a constexpr
g++-4.9.1 和 clang++-3.4.2 都会发生这种情况。
下面是一个小测试程序,用于快速简单的实验。
#include <utility>
#include <array>
#include <iostream>
// utils
template <size_t N> using require_constexpr = std::make_index_sequence<N>;
template <typename...> constexpr void noop (void) { }
// size() wrappers
template <typename T> constexpr std::size_t size (T obj) { return obj.size(); }
template <typename T> constexpr auto sz1 (T obj) { return size(require_constexpr< obj.size() > { }); }
template <typename T> constexpr auto sz2 (T obj) { return size(require_constexpr< size(obj) > { }); }
int main0 (int, char**)
{
constexpr auto const ar = std::array<int, 4u> { 4, 5, 6, 7 };
// Check constexpr-computability of size(), sz1() and the expansion of sz2()
noop<
require_constexpr<
size(require_constexpr< ar.size() > { }) + sz1(ar) +
size(require_constexpr< size(ar) > { })
>
>();
// But this is an error
// ERROR: "obj" is not a constexpr in sz2()
//noop< require_constexpr< sz2(ar) > >();
return 0;
}
编辑这是相关的编译输出。
叮当
src/main1.cpp:12:87: error: non-type template argument is not a constant expression
template <typename T> constexpr auto sz2 (T obj) { return size(require_constexpr< size(obj) > { }); }
^~~~~~~~~
src/main1.cpp:28:32: note: in instantiation of function template specialization 'sz2<std::array<int, 4> >' requested here
noop< require_constexpr< sz2(ar) > >();
^
src/main1.cpp:12:92: note: read of non-constexpr variable 'obj' is not allowed in a constant expression
template <typename T> constexpr auto sz2 (T obj) { return size(require_constexpr< size(obj) > { }); }
^
src/main1.cpp:12:92: note: in call to 'array(obj)'
src/main1.cpp:12:49: note: declared here
template <typename T> constexpr auto sz2 (T obj) { return size(require_constexpr< size(obj) > { }); }
^
gcc
src/main1.cpp: In substitution of ‘template<long unsigned int N> using require_constexpr = std::make_index_sequence<N> [with long unsigned int N = size<std::array<int, 4ul> >(obj)]’:
src/main1.cpp:12:102: required from ‘constexpr auto sz2(T) [with T = std::array<int, 4ul>]’
src/main1.cpp:28:38: required from here
src/main1.cpp:12:102: error: ‘obj’ is not a constant expression
template <typename T> constexpr auto sz2 (T obj) { return size(require_constexpr< size(obj) > { }); }
^
src/main1.cpp:12:102: note: in template argument for type ‘long unsigned int’
【问题讨论】:
-
有趣。如果这是预期的标准行为,我会感到惊讶。我可以猜测这是两个编译器中的错误......?很难相信,因为它在两个编译器中都发生了相同的情况,考虑到
constexpr是相对较新实现的,并不难相信。