【发布时间】:2016-10-05 02:46:44
【问题描述】:
我有一些通用代码想知道何时传递了一系列对象,这些对象的数量在编译时是已知的,因为它可以选择一种替代算法策略。为此,我尝试编写一个has_constexpr_size(T) constexpr 函数,如下所示,它试图探测T 的size() 成员函数,看看它是否可以作为constexpr 执行。
请注意,这里与通常的“我可以检测 constexpr 执行上下文吗?”有一个关键区别。问题是因为某些 STL 容器(如 array<T> always)提供了一个 constexpr-available size() 函数,而其他 STL 容器如 initializer_list<T> 获得一个 constexpr-available size() 函数当且仅当初始化列表本身是 constexpr (因为实现取决于内部指针对,并且那些需要是 constexpr 以使 size() 具有全 constexpr 输入)。因此,has_constexpr_size(T) 函数采用一个正在测试的 T 类型的实例,以便它可以检测这两种情况。
这是一个测试用例:
#include <array>
#include <type_traits>
#include <utility>
#include <vector>
namespace type_traits
{
namespace detail
{
template <size_t N> struct Char
{
char foo[N];
};
template <class T> constexpr inline Char<2> constexpr_size(T &&v) { return (v.size(), true) ? Char<2>() : throw 0; }
template <class T> inline Char<1> constexpr_size(...) { return Char<1>(); }
}
//! Returns true if the instance of v has a constexpr size()
template <class T> constexpr inline bool has_constexpr_size(T &&v)
{
return noexcept(detail::constexpr_size<T>(std::forward<T>(v)));
}
// Non-constexpr array (always has a constexpr size())
auto ca=std::array<int, 2>();
// Constexpr initializer_list (has constexpr size()). Note fails to compile on VS2015 as its initializer_list isn't constexpr capable yet
constexpr std::initializer_list<int> cil{1, 2};
// Non-constexpr initializer_list (does not have constexpr size())
std::initializer_list<int> il{1, 2};
// Non-constexpr vector (never has constexpr size())
std::vector<int> vec{1, 2};
// Passes on GCC 4.9 and clang 3.8
static_assert(ca.size(), "non-constexpr array size constexpr");
// Passes on GCC 4.9 and clang 3.8
static_assert(cil.size(), "constexpr il size constexpr");
// Fails as you'd expect everywhere with non-constexpr il error
//static_assert(il.size(), "non-constexpr il size constexpr");
// Passes on GCC 4.9, fails on VS2015 and clang 3.8
static_assert(has_constexpr_size(ca), "ca"); // Should NOT fail on VS2015 and clang 3.8
// Fails on GCC 4.9 and clang 3.8. VS2015 doesn't apply.
static_assert(has_constexpr_size(cil), "cil"); // FAILS, and it should not!
// Passes, correct
static_assert(!has_constexpr_size(il), "il");
// Passes, correct
static_assert(!has_constexpr_size(vec), "vec");
constexpr bool test()
{
return has_constexpr_size(std::initializer_list<int>{1, 2});
}
constexpr bool testval=test();
// Fails on GCC 4.9 and clang 3.8. VS2015 doesn't apply.
static_assert(testval, "test()");
}
您会注意到 array<T>::size() 和 constexpr initializer_list<T>::size() 的直接静态断言在所有编译器上都能正常工作,正如您所期望的那样。我的has_constexpr_size(T) 函数适用于array<T>,但仅适用于 GCC 4.9,我认为这是因为 GCC 的特别宽容的 constexpr 实现。我的 has_constexpr_size(T) 函数在所有编译器上的 constexpr initializer_list<T> 都失败。
所以我的问题是:
是否可以编写一个
has_constexpr_size(T)函数来正确检测array<T>和constexprinitializer_list<T>的constexpr 可用size()成员函数以及提供constexpr 可用size()函数的任何其他类型?如果当前在 C++ 或当前编译器中无法实现 (1),是否可以编写一个
has_constexpr_size(T)函数来正确检测array<T>的 constexpr-availablesize()成员函数以及提供的任何其他类型一个始终可用的 constexprsize()函数? 注意此解决方案不检查是否仅存在某些size()函数,而是检查它是否为 constexpr-available。所以has_constexpr_size(std::vector<int>())会是假的。
【问题讨论】:
标签: c++ c++11 template-meta-programming constexpr