CRTP、模板、元编程、转发和静态成员:g++ 4.8 中的一个错误
CRTP, templates, metaprogramming, forwarding and static member: a bug in g++ 4.8?
首先,对于这段代码的质量差,我真的很抱歉,但我已经花了 1 个小时来隔离问题的根源,我没有比这更短的例子。所以这是代码:
#include <iostream>
#include <type_traits>
#include <utility>
#include <tuple>
#include <array>
template <class Crtp, class... Types>
struct Base
{
template <
unsigned int Index,
class Type = typename std::tuple_element<Index, std::tuple<Types...> >::type
>
inline const Type& get() const {
return std::get<Index>(data);
}
template <
unsigned int Index,
class Type = typename std::tuple_element<Index, std::tuple<Types...> >::type
>
inline Crtp& set(const Type& value) {
std::get<Index>(data) = value; return static_cast<Crtp&>(*this);
}
std::tuple<Types...> data;
};
template <typename Type, unsigned int Size>
struct Derived : public Base<Derived<Type, Size>, std::array<Type, Size>>
{
template <
class... Args,
class Template = decltype(std::declval<const Base<
Derived<Type, Size>,
std::array<Type, Size>
>>().template get<0>(std::declval<Args>()...))
>
inline Template test(Args&&... args) const {
return this->template get<0>(std::forward<Args>(args)...);
}
template <
class... Args,
class Template = decltype(std::declval<const Base<
Derived<Type, Size>,
std::array<Type, Size>
>>().template set<0>(std::declval<Args>()...))
>
inline Derived<Type, Size>& test(Args&&... args) {
return this->template set<0>(std::forward<Args>(args)...);
}
static void check() {
Derived<double, 3> derived;
std::cout<<derived.test()[0]<<std::endl;
}
};
int main(int argc, char* argv[])
{
Derived<double, 3> derived;
std::cout<<derived.test()[0]<<std::endl; // Working
Derived<double, 3>::check(); // Not working: error: no match for ‘operator[]’ (operand types are ‘Derived<double, 3u>’ and ‘int’)
return 0;
}
说明所做的事情:有一个 Base
类将派生类 (CRTP( 和元组类型作为模板参数。这个基类有两个成员:一个用于get
tuple
的第n个元素,另一个用于set
tuple
的第n个元素。然后,有一个从Base
类继承的Derived
类,并将std::array
放在基类的元组中:因此,该派生类的数据类型为:std::tuple<std::array<Type, Size>> data
。这个派生类有一个重载函数test()
该函数根据其参数调用get
或set
函数:test()
将调用get()
但test(std::array<double, 3>{1, 2, 3})
将调用set(std::array<double, 3>{1, 2, 3})
。因此test()[0]
应该返回数组的第一个元素:它在main()
中工作,但在静态函数中不起作用。
我不知道编译器试图做什么,但显然这是行不通的。我认为这是g++ 4.8.1
中的一个错误(我没有尝试过其他版本(,但我想确定这一点。
所以这是我的问题:
- 你能确认这个错误(也许找到一个解释(吗?
- 您是否有一个更短且不太复杂的示例来说明问题?
编译器试图做什么"在调用时错误地在Derived::test
的常量和非常量重载之间执行重载解析check()
。您可以通过插入看到
std::cout << typeid(decltype(derived.test())).name() << std::endl;
在check()
("7DerivedIdLj3EE"(和main()
("St5arrayIdLy3EE"(中。
编辑:一些调查,交替注释掉常量/非常量测试重载,表明模板推导对于check()
中test
的非恒定重载并没有失败。参数包Args
为空,因此替换失败应发生在确定不带参数的set<0>
的返回类型的decltype
表达式中。
当你在思考为什么时,我建议你简化你的代码以避免它:
#include <iostream>
#include <utility>
#include <tuple>
#include <array>
template <class Crtp, class... Types>
struct Base
{
std::tuple<Types...> data;
template <unsigned int Index>
auto get() const -> decltype(std::get<Index>(data)) {
return std::get<Index>(data);
}
template <unsigned int Index, typename T>
Crtp& set(T&& value) {
std::get<Index>(data) = std::forward<T>(value);
return static_cast<Crtp&>(*this);
}
};
template <typename Type, unsigned int Size>
struct Derived : public Base<Derived<Type, Size>, std::array<Type, Size>>
{
auto test() const -> decltype(this->template get<0>()) {
return this->template get<0>();
}
template <typename T>
Derived& test(T&& value) {
return this->template set<0>(std::forward<T>(value));
}
static void check() {
Derived<double, 3> derived;
std::cout << derived.test()[0] << std::endl;
}
};
int main(int, char*[])
{
Derived<double, 3> derived;
std::cout << derived.test()[0] << std::endl;
Derived<double, 3>::check();
}
- C++,我收到一个无法理解的编译器错误
- VSCode-有一个红色下划线,但程序构建和运行正确,并且出现配音错误
- 删除映射和分割错误中的一个过去结束元素
- 为什么我的 heap.h 文件给我一个LNK2001错误?
- 写一个分数类,我无法弄清楚这些错误
- 我在 .h 中有一个枚举类,并且在.cpp错误中有一个运算符重载:与"运算符<<不匹配
- 一个标头库中的错误
- 给定一个整数数组,需要在Max_Heap上运行操作。得到错误"segmentation fault",有什么想法吗?(C++)
- 使用Visual Studio在虚幻引擎中创建一个新的类c ++给了我太多的错误
- 我正在尝试制作一个自平衡机器人,但编译时存在错误。我不知道如何解决它
- 试图修复一个错误,该错误不会让我开始编程其余部分
- MSVC 无法根据模板参数进行数学运算,这是一个错误吗?
- 我正在尝试一个傻瓜 C++ 练习,我遇到了一个错误,说类 'GraduateStudent' 没有任何名为 'advisor' 的字段
- 零四元数和任何向量都不为零的特征积,这是一个错误吗?
- 我有一个线程 1:EXC_BAD_ACCESS(代码 = 1,地址 = 0x8)错误.我认为这是由于内存管理不好.我可以
- 两个线程一个使用流 Api,另一个线程创建文件失败并出现错误ERROR_SHARING_VIOLATION
- 在使用堆栈为下一个最大数字编写代码时面临 SIGSEGV(分段错误)
- LNK2019错误一个DLL链接到MFC DLL
- 错误:一个声明中有多个类型
- 带有两个运算符的C++11模糊错误(一个左值-第二个右值).底部的