Я столкнулся с очень странной ошибкой компилятора.По какой-то причине опубликованный код правильно компилируется с g ++ (7.3.0), а clang (7.0.0) дает сбой:
../TemplateAlias/main.cpp:64:9: error: no matching function for call to 'freeFunc'
freeFunc(new Func, dummyField);
^~~~~~~~
../TemplateAlias/main.cpp:73:12: note: in instantiation of member function 'Helper<Traits<double, ConcreteData, ConcreteField> >::func' requested here
helper.func();
^
../TemplateAlias/main.cpp:21:13: note: candidate template ignored: deduced conflicting templates for parameter '' ('FieldData' vs. 'ConcreteData')
static void freeFunc(SomeFunc<T, FieldData>* func,
^
Для обоих параметров компилятора было задано -std = c ++ 14
template<typename T>
struct ConcreteData
{
T data;
};
template<typename T, template<typename U> class FieldData>
struct ConcreteField
{
FieldData<T> someMember;
};
template<typename T, template<typename U> class FieldData>
struct SomeFunc
{
};
template<typename T, template<typename U> class FieldData>
static void freeFunc(SomeFunc<T, FieldData>* func,
ConcreteField<T, FieldData>& field)
{
// apply the func on data
(void)field; // silence compiler warning
delete func;
}
template<
typename ScalarType,
template<typename U> class FieldDataType,
template<typename U, template <typename X> class Data> class FieldType
>
struct Traits
{
using Scalar = ScalarType;
template<typename T>
using FieldData = FieldDataType<T>;
using Field = FieldType<Scalar, FieldDataType>; // fails with clang only
// using Field = FieldType<Scalar, FieldData>; // using this line helps clang
};
template<typename Traits>
struct Helper
{
// alias all types given by trait for easier access
using Scalar = typename Traits::Scalar;
using Field = typename Traits::Field;
template<typename U>
using DataAlias = typename Traits::template FieldData<U>;
void func()
{
// using Func = SomeFunc<Scalar, DataAlias>; // this line is intended, but fails with both GCC and clang
using Func = SomeFunc<Scalar, Traits::template FieldData>; // compiles only with GCC, fails with clang
Field dummyField;
freeFunc(new Func, dummyField);
}
};
int main()
{
using ConcreteTraits = Traits<double, ConcreteData, ConcreteField>;
Helper<ConcreteTraits> helper;
helper.func();
return 0;
}
Согласно cppreference.com:
Объявление псевдонима типа вводит имя, которое можно использовать как синоним для типа, обозначаемого идентификатором типа.Он не вводит новый тип и не может изменить значение имени существующего типа.Нет разницы между объявлением псевдонима типа и объявлением typedef.Это объявление может появляться в области блока, области класса или области пространства имен.
и
Шаблоны псевдонимов никогда не выводятся путем вывода аргумента шаблона при выводе параметра шаблона шаблона.
В моем понимании оба типа (ConcreteData и FieldData) должны быть эквивалентны.Почему в этом состоянии происходит сбой clang и почему оба компилятора терпят неудачу при использовании псевдонима «второй этап»?Какой компилятор прав в соответствии со стандартом C ++?Это ошибка компилятора или тонкая неоднозначная интерпретация стандарта C ++ 14?