Я столкнулся с ошибкой компиляции в некотором сложном коде шаблона 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]
, та же самая логика c, скомпилированная просто отлично, разбилась на 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<>()
line, и дополнительно сообщает мне, что строка others2[idx]->OtherMethod<>()
, которая работала в g ++, на самом деле неверна!
Конечно, если я изменю код 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 слишком строг для этой логики c? И действительно ли обходной путь, разделяющий строку others1[idx]->OtherMethod<>()
на две части (с временной переменной), действительно корректен, или он также должен как-то использовать ключевое слово "template"?