我编写了一个constexpr函数,用于计算元组元素大小的总和.
直接调用时,函数调用将使用值元组和引用元组进行编译.
当通过模板化函数调用时,它仍然使用值元组编译,但是使用引用元组失败.
我可以使用指针元组而不是参考元组来解决我的问题,但我写的东西的API(一组模板化的功能,以便于为微控制器编写SPI和I²C驱动程序)将不那么干净.
谢谢你的帮助.
Ps:我正在使用gcc8.2使用c ++ 17标准.
亚历山大
#include <tuple>
template <typename> struct is_tuple_t: std::false_type {};
template <typename ...T> struct is_tuple_t<std::tuple<T...>> : std::true_type {};
template<typename Type>
constexpr bool is_tuple(const Type&) {
if constexpr (is_tuple_t<Type>::value)
return true;
else
return false;
}
template<class F, class...Ts, std::size_t...Is>
constexpr void for_each_in_tuple(const std::tuple<Ts...> & tupl, F func,
std::index_sequence<Is...>){
using expander = int[];
(void)expander { 0, ((void)func(std::get<Is>(tupl)), 0)... };
}
template<class F, class...Ts>
constexpr void for_each_in_tuple(const std::tuple<Ts...> & tupl, F func){
for_each_in_tuple(tupl, func, std::make_index_sequence<sizeof...(Ts)>());
}
template <typename T>
constexpr size_t size_of_tuple(const T &tup) {
static_assert(is_tuple(tup) == true, "error size_of_tuple argument must be a tuple");
size_t s=0;
for_each_in_tuple(tup, [&s](auto &&x) {
s += sizeof(x);
});
return s;
}
template<typename Tb>
constexpr size_t foo(const Tb&& tup)
{
constexpr size_t st = size_of_tuple(tup);
return st;
}
int main()
{
uint16_t var;
constexpr size_t s1 = size_of_tuple(std::make_tuple(1)) ; // OK
constexpr size_t s2 = size_of_tuple(std::forward_as_tuple(var)) ; // OK
constexpr size_t f1 = foo(std::make_tuple(1)) ; // OK
constexpr size_t f2 = foo(std::forward_as_tuple(var)) ; // FAIL
}
Run Code Online (Sandbox Code Playgroud)
template<typename Tb>
constexpr size_t foo(const Tb&& tup)
{
constexpr size_t st = size_of_tuple(tup);
return st;
}
Run Code Online (Sandbox Code Playgroud)
在此函数中,tup不是常量表达式,因此不能在constexpr变量的初始值设定项中使用。
[expr.const]¶2
表达式
e是核心常量表达式,除非 [...] 的计算e将计算以下表达式之一:
- [...]
- 引用引用类型的变量或数据成员的 id 表达式,除非引用具有前面的初始化并且
- 它用常量表达式初始化或
- 它的生命周期开始于评估
e
其中任何一个都应该起作用:
template<typename Tb>
constexpr size_t foo(const Tb&& tup)
{
size_t st = size_of_tuple(tup);
return st;
}
template<typename Tb>
constexpr size_t foo(const Tb&& tup)
{
return size_of_tuple(tup);
}
Run Code Online (Sandbox Code Playgroud)
请注意,Clang 仍会拒绝您的代码,因为您的代码还违反了同一规则。
最终,您的size_of_tuple和is_tuple都有缺陷,因为如果它们的参数是引用,则它们不能在常量表达式中使用。如果你想使用这种类似函数的语法,你需要type_c来自 Boost.Hana 的类似语法:
template <typename T>
class type {};
template <typename T>
constexpr type<T> type_c{};
template <typename T>
constexpr bool is_tuple(type<T>) {
return is_tuple_t<T>::value;
}
template <typename T>
constexpr size_t size_of_tuple(type<T> tup) {
static_assert(is_tuple(tup), "size_of_tuple argument must be a tuple");
//...
}
template<typename Tb>
constexpr size_t foo(const Tb&& tup)
{
size_t st = size_of_tuple(type_c<std::remove_cvref_t<decltype(tup)>>);
return st;
}
uint16_t var = 42;
constexpr size_t f2 = foo(std::forward_as_tuple(var));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
160 次 |
| 最近记录: |