GCC4 模板错误或更可能的 ID10t 错误
gcc4 template bug or more likely id10t error
下面的代码在Visual Studio下编译得很好,但gcc 4.6.2或4.7都无法处理它。 它似乎是有效的,但 gcc 似乎无法解决常量和非常量参数之间的差异。 这可能是编译器错误吗?
struct CReadType{};
struct CWriteType{};
template<typename ReadWriteType, typename T>
struct AddPkgrConstByType {};
template<typename T>
struct AddPkgrConstByType<CReadType, T> {
typedef T type;
};
template<typename T>
struct AddPkgrConstByType<CReadType, const T> {
typedef T type;
};
template<typename T>
struct AddPkgrConstByType<CWriteType, T> {
typedef T const type;
};
template<typename Packager, typename T>
struct AddPkgrConst : public AddPkgrConstByType<typename Packager::CReadWriteType, T> {
};
template<typename Packager, typename T>
inline bool Package( Packager* ppkgr, T* pt )
{
return true;
}
template<typename Packager>
inline bool Package( Packager* ppkgr, typename AddPkgrConst<Packager,bool>::type* pb)
{
return false;
}
struct ReadPackager {
typedef CReadType CReadWriteType;
};
struct WritePackager {
typedef CWriteType CReadWriteType;
};
int main(int argc, char* argv[])
{
ReadPackager rp;
WritePackager wp;
bool b = true;
const bool cb = false;
Package( &rp, &b );
}
编译器调用:
g++ -fPIC -O -std=c++0x -Wno-deprecated -D_REENTRANT
g++-D__STDC_LIMIT_MACROS -c test.cpp
test.cpp: In function ‘int main(int, char**)’:
test.cpp:58:22: error: call of overloaded ‘Package(ReadPackager*, bool*)’ is ambiguous
test.cpp:58:22: note: candidates are:
test.cpp:31:6: note: bool Package(Packager*, T*) [with Packager = ReadPackager, T = bool]
test.cpp:38:6: note: bool Package(Packager*, typename AddPkgrConst<Packager, bool>::type*) [with Packager = ReadPackager, typename AddPkgrConst<Packager, bool>::type = bool]
这对我来说看起来像一个编译器错误。这里涉及的问题是重载解析和模板函数的部分排序。由于两个模板函数都可以匹配参数列表(ReadPackager*, bool)
,因此应该使用模板函数的部分顺序来选择更专业的模板函数。
始终可以用作另一个函数的参数,则该模板函数至少与另一个函数一样专用。
很明显,任何两个指针参数都与第一个 Package(( 函数匹配,但例如 Package(ReadPackager*, const int*( 不能匹配第二个函数。这似乎意味着第二个 Package 函数更专业,应该解决任何歧义。
但是,由于编译器之间存在分歧,因此可能会涉及一些被简化解释所忽略的微妙之处。因此,我将按照从标准中确定函数模板部分排序的过程来识别正确的行为。
首先,将函数标记为 P1 和 P2 以便于参考。
小一:
template<typename Packager, typename T>
bool Package( Packager* ppkgr, T* pt );
小二:
template<typename Packager>
bool Package( Packager* ppkgr, typename AddPkgrConst<Packager,bool>::type* pb);
该标准规定,对于每个模板函数(T1(,我们必须为其每个模板参数泛型唯一类型,使用这些类型来确定函数调用参数类型,然后使用这些类型推导出其他模板(T2(中的类型。如果此操作成功,则第一个模板 (T1( 至少与第二个模板 (T2( 一样专用。第一个小一至小一>
小一- 合成 P2 模板参数
Packager
的唯一类型U
。 - 对
P1
的参数列表执行类型推断。Packager
被推导出为U
,T
被推导出为AddPkgrConst<Packager,U>::type
。
这成功了,P1被判断为不比P2更专业。
现在 P1->P2:
- 合成模板参数
U1
和U2
的唯一类型Packager
和 P1 的T
,获取参数列表(U1*、U2*(。 - 对
P2
的参数列表执行类型推断。Packager
被推算为 U1。 - 不会对第二个参数执行推导,因为作为依赖类型,它被视为非推导上下文。
- 因此,第二个参数是
AddPkgrConst<U1,bool>::type
,其计算结果为bool
。这与第二个参数U2
不匹配。
如果我们继续执行步骤 4,此过程将失败。但是,我怀疑拒绝此代码的编译器不执行步骤 4,因此仅仅因为类型推断成功而认为 P2 并不比 P1 更专业。这似乎违反直觉,因为 P1 明确接受 P2 所做的任何输入,反之亦然。标准的这一部分有些复杂,因此不清楚是否需要进行最终比较。
让我们尝试通过应用 §14.8.2.5 第 1 段从类型推导模板参数来解决这个问题
可以在几个不同的上下文中推导模板参数,但在每种情况下,将根据模板参数指定的类型(称为 P(与实际类型(称为 A(进行比较,并尝试查找模板参数值(类型参数的类型、非类型参数的值、 或模板参数的模板(,这将使 P 在替换推导值(称为推导的 A(后与 A 兼容。
在我们的类型推导中,推导的 A 是 AddPkgrConst<U1,bool>::type
= bool
。这与原始 A 不兼容,原始 A 是唯一类型 U2
.这似乎支持了偏序解决歧义的立场。
Visual Studio有什么问题,但gcc
说的似乎是对的:
您实例化AddPkgrConstByType<CReadType, T>
Packager::CReadWriteType
因为解析为CReadType
。因此,AddPkgrConst<Packager,bool>::type
将根据第一个实现(不是专业化(解决bool
。这意味着您有两个具有相同参数列表的单独函数专用化,C++不允许这样做。
由于函数模板不能专用化,因此此处有两个函数模板重载。这两个重载都能够接受bool*
作为它们的第二个参数,因此它们似乎被 g++ 正确地检测为不明确。
但是,类可以部分专用,以便只选择一个版本,并且您可以使用包装魔法来实现所需的目标。我只粘贴我添加的代码。
template <typename Packager, typename T>
struct Wrapper
{
static bool Package()
{
return true;
}
};
template <typename Packager>
struct Wrapper<Packager, typename AddPkgrConst<Packager,bool>::type>
{
static bool Package()
{
return false;
}
};
template <typename Packager, typename T>
Wrapper<Packager, T> make_wrapper(Packager* /*p*/, T* /*t*/)
{
return Wrapper<Packager, T>();
}
int main()
{
ReadPackager rp;
bool b = true;
std::cout << make_wrapper(&rp, &b).Package() << std::endl; // Prints out 0.
}
- 警告处理为错误这里有什么问题
- "error: no matching function for call to"构造函数错误
- boost::进程间消息队列引发错误
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- QT在错误的班级中寻找空位
- vector.resize()中的分配错误
- 代码在main()中运行,但在函数中出现错误
- 释放错误后堆使用
- (C++)分析树以计算返回错误值的简单算术表达式
- Project Euler问题4的错误解决方案
- 我的字符计数代码计算错误.为什么
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 尝试导入pybind-opencv模块时出现libgtk错误
- CMake项目Boost库错误:Boost/config/compiler/gcc.hpp:165:10:致命错误:cs
- 在某些循环内使用vector.push_back时出现分段错误
- MSVC多行宏编译器错误
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- GCC4 模板错误或更可能的 ID10t 错误