【发布时间】:2020-06-17 15:23:42
【问题描述】:
我在一些复杂的 C++ 模板代码中遇到了编译错误,我已将其简化如下:
struct MyOptions
{
static const size_t maxArray = 2;
static const uint maxIdx = 8;
};
class OtherClass
{
uint num;
public:
OtherClass(uint val) : num(val)
{
}
void OtherCall(const char *varName, uint arraySize)
{
std::cout << '#' << num << ": " << varName << '[' << arraySize << ']' << std::endl;
}
template <class OPTS_> inline void OtherMethod(const char *varName)
{
OtherCall(varName, OPTS_::maxIdx);
}
};
template <size_t COUNT_> class ConstArray
{
OtherClass *other[COUNT_];
public:
ConstArray(OtherClass *o1, OtherClass *o2) // Just sample logic, shouldn't hard-code 2 elements
{
other[0] = o1;
other[1] = o2;
}
inline OtherClass *operator[](size_t idx) const
{
return other[idx]; // Array itself not changeable by caller
}
};
template <class OPTS_> class MyClass
{
ConstArray<OPTS_::maxArray> others1;
ConstArray<2> others2;
public:
MyClass(OtherClass *o1, OtherClass *o2) : others1(o1, o2), others2(o1, o2)
{ // Just test code to initialize the ConstArray<> members
}
inline void PrintInfo(uint idx, const char *varName)
{
OtherClass *other1Ptr = others1[idx];
other1Ptr->OtherMethod<OPTS_>(varName); // This works
others1[idx]->OtherMethod<OPTS_>(varName); // This FAILS!!
others2[idx]->OtherMethod<OPTS_>(varName); // This works
}
};
int main(int argc, char *argv[])
{
OtherClass a(9), b(42);
MyClass<MyOptions> mine(&a, &b);
mine.PrintInfo(1, "foo");
return 0;
}
g++ 5.4.0 中“This FAILS!!”的错误消息上面的行是
error: expected primary-expression before ‘>’ token
others1[idx]->OtherMethod<OPTS_>(varName); // This FAILS!!
^
然而,显然当我使用临时的other1Ptr = others1[idx] 时,相同的逻辑编译得很好,分成了 2 个语句,这让我相信这是一个 g++ 错误。
但我使用在线编译器在 Clang 中尝试,得到了不同的(和冲突的)错误:
error: use 'template' keyword to treat 'OtherMethod' as a dependent template name
others1[idx]->OtherMethod<OPTS_>(varName); // This fails
^
template
error: use 'template' keyword to treat 'OtherMethod' as a dependent template name
others2[idx]->OtherMethod<OPTS_>(varName); // This works
^
template
2 errors generated.
所以 Clang 告诉我 others1[idx]->OtherMethods<>() 行实际上有什么问题,并另外告诉我在 g++ 中工作的 others2[idx]->OtherMethod<>() 行实际上是错误的!
果然,如果我更改 PrintInfo() 代码,它在 Clang 中编译得很好:
inline void PrintInfo(uint idx, const char *varName)
{
OtherClass *other1Ptr = others1[idx];
other1Ptr->OtherMethod<OPTS_>(varName); // This works
// others1[idx]->OtherMethod<OPTS_>(varName); // This FAILS!!
others1[idx]->template OtherMethod<OPTS_>(varName); // This works
// others2[idx]->OtherMethod<OPTS_>(varName); // This works ONLY IN g++!
others2[idx]->template OtherMethod<OPTS_>(varName); // This works
}
而且这段代码在 g++ 中也编译得很好,所以看起来这是正确的行为。
然而正如我们已经看到的,g++ 也接受了
others2[idx]->OtherMethod<OPTS_>(varName); // This works ONLY IN g++!
那么这是 g++ 中的错误吗?还是 Clang 对这个逻辑太严格了?解决方法是将others1[idx]->OtherMethod<>() 行分成两部分(带有一个临时变量)实际上是否正确,还是应该以某种方式使用“模板”关键字?
【问题讨论】:
-
您是否尝试将
maxArray声明为constexpr而不是const? -
否;我可以尝试一下,并怀疑它可能会使
ConstArray<OPTS_::maxArray>案例像 g++ 中的ConstArray<2>一样工作。尽管考虑到 Clang 的行为,这似乎与此时的问题无关。编辑:不,它不会改变 g++ 的行为。 -
在某些情况下
template是可选的,请参阅stackoverflow.com/questions/610245/… -
显示相同差异的更简单代码:godbolt.org/z/DfRiv6
-
我猜这是一个 Clang 错误。当前主干 Clang 同意 GCC。
标签: c++ templates compiler-errors g++ clang