C++ gcc4模板错误或更可能的id10t错误
下面的代码在VisualStudio下编译得很好,但GCC4.6.2或4.7都无法处理。它似乎是有效的,但gcc似乎无法解决常量和非常量参数之间的差异。这可能是一个编译器错误吗C++ gcc4模板错误或更可能的id10t错误,c++,templates,gcc,compiler-construction,gcc4,C++,Templates,Gcc,Compiler Construction,Gcc4,下面的代码在VisualStudio下编译得很好,但GCC4.6.2或4.7都无法处理。它似乎是有效的,但gcc似乎无法解决常量和非常量参数之间的差异。这可能是一个编译器错误吗 struct CReadType{}; struct CWriteType{}; template<typename ReadWriteType, typename T> struct AddPkgrConstByType {}; template<typename T> struct A
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 );
}
struct-CReadType{};
结构CWriteType{};
模板
结构AddPkgrConstByType{};
模板
结构AddPkgrConstByType{
T型;
};
模板
结构AddPkgrConstByType{
T型;
};
模板
结构AddPkgrConstByType{
typedef T const type;
};
模板
结构AddPkgrConst:public AddPkgrConstByType{
};
模板
内联bool包装(包装商*ppkgr,T*pt)
{
返回true;
}
模板
内联布尔包(包装商*ppkgr,类型名AddPkgrConst::类型*pb)
{
返回false;
}
结构读取器{
typedef CReadType CReadWriteType;
};
结构写包器{
typedef CWriteType CReadWriteType;
};
int main(int argc,char*argv[])
{
阅读器包装机;
WritePackager wp;
布尔b=真;
const bool cb=假;
包装(&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]
g++-fPIC-O-std=c++0x-Wno已弃用-D_可重入
g++-D_ustdc_LIMIT_宏-c test.cpp
test.cpp:在函数“int main(int,char**)”中:
test.cpp:58:22:错误:重载的“Package(ReadPackager*,bool*)”调用不明确
考试。cpp:58:22:注:考生为:
test.cpp:31:6:注:bool包(Packager*,T*)[带Packager=ReadPackager,T=bool]
test.cpp:38:6:注:bool包(Packager*,typename AddPkgrConst::type*)[带Packager=ReadPackager,typename AddPkgrConst::type=bool]
我不知道Visual Studio有什么问题,但是gcc
所说的似乎是正确的:
实例化
AddPkgrConstByType
是因为Packager::CReadWriteType
解析为CReadType
。因此,AddPkgrConst::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.
}
模板
结构包装器
{
静态bool包()
{
返回true;
}
};
模板
结构包装器
{
静态bool包()
{
返回false;
}
};
模板
包装机制造包装机(包装机*/*p*/,T*/*T*/)
{
返回包装器();
}
int main()
{
阅读器包装机;
布尔b=真;
std::cout这在我看来像是编译器错误。这里涉及的问题是模板函数的重载解析和偏序。由于两个模板函数都可以匹配参数列表(ReadPackager*,bool)
,因此应该使用模板函数的偏序来选择更专业的模板函数
简单地说,如果一个模板函数的参数始终可以用作另一个模板函数的参数,那么该模板函数至少与另一个模板函数一样专用
很明显,任何两个指针参数都与第一个Package()函数匹配,但例如Package(ReadPackager*,const int*)不能与第二个匹配。这似乎意味着第二个Package函数更专业,应该解决任何歧义
但是,由于编译器之间存在分歧,因此可能会涉及一些被简化解释忽略的微妙之处。因此,我将遵循从标准中确定函数模板偏序的过程,以识别正确的行为
首先,将函数标记为P1和P2以便于参考
P1:
模板
bool包装(包装商*ppkgr,T*pt);
P2:
模板
bool包装(包装商*ppkgr,类型名称AddPkgrConst::类型*pb);
该标准规定,对于每个模板函数(T1),我们必须为其每个模板参数创建泛型唯一类型,使用这些类型确定函数调用参数类型,然后使用这些类型推断其他模板(T2)中的类型。如果成功,则第一个模板(T1)至少与第二个模板(T2)一样专用。
第一个P2->P1
为P2的模板参数Packager
合成唯一类型U
对P1
的参数列表执行类型推断。Packager
被推断为U
,T
被推断为AddPkgrConst::type
此操作成功,P1被判断为不比P2更专业化
现在P1->P2:
合成P1的模板参数Packager
和T
的唯一类型U1
和U2
,以获得参数列表(U1*,U2*)
根据P2
的参数列表执行类型推断。包装商
推断为U1
第二个参数不执行推断,因为它是依赖类型,被视为非推断上下文
因此,第二个参数是AddPkgrConst::type
,其计算结果为bool
。这与第二个参数U2
不匹配
< P >这个过程如果我们进入第4步失败了。然而,我怀疑,拒绝这个代码的编译器不执行步骤4,因此认为P2没有比P1更专业化,仅仅因为类型推导成功。这似乎是违反直觉的,因为P1清楚地接受了P2所做的任何输入,反之亦然。dard有些复杂,所以不清楚最后的比较
template<typename Packager, typename T>
bool Package( Packager* ppkgr, T* pt );
template<typename Packager>
bool Package( Packager* ppkgr, typename AddPkgrConst<Packager,bool>::type* pb);