Clang и GCC не согласны с автоматическим спецификатором для параметра нестандартного шаблона в литье С++ 17
У меня в основном есть класс, который зависит от параметра шаблона, отличного от типа. Я определил кастинг таким образом, чтобы объект шаблона N
мог преобразовать в другой из M
У меня есть минимальный пример, который может воспроизвести ситуацию:
template<auto Integral>
class Test{
public:
typedef decltype(Integral) value_type;
static constexpr value_type N = Integral;
constexpr Test (const value_type& x = 0);
template<auto Integral2>
constexpr explicit operator Test<Integral2>() const;
private:
value_type n;
};
template<auto Integral>
constexpr Test<Integral>::Test (const value_type& x){
if (x < 0){
n = N - (-x)%N;
}
else{
n = x%N;
}
}
template<auto Integral> template<auto Integral2>
constexpr Test<Integral>::operator Test<Integral2>() const{
return Test<Integral2>(n%(Test<Integral2>::N));
}
Я компилирую GCC 7.2.0 и Clang 5.0.0 в Ubuntu 16.04 LTS с флагами -O2 -std=c++17
.
Проблема в том, что я все время скомпилировал с помощью g++, и все работало, как ожидалось, но затем я попробовал clan g++, чтобы проверить, все ли еще компилируется.
К моему удивлению, это было не так, поскольку клан g++ жаловался на некоторые части, которые g++ этого не делал. Вы можете проверить представление diff в Compiler Explorer.
Одним из сообщений об ошибках, которые создает клан g++, является:
error: out-of-line definition of 'operator Test<Integral2>' does not match any declaration in 'Test<Integral>'
Это заставляет меня думать, что клан g++ не нашел "правильной" декларации о конверсии, но я не знаю.
Примечание. Эта первая ошибка появляется только при отмене объявления из определения. В противном случае это кажется правильным.
Это вторая ошибка, создаваемая кланом g++:
error: a non-type template parameter cannot have type 'auto'
Но это меня еще больше удивляет, потому что ошибка говорит о том, что должно быть допустимо в С++ 17. Наверное, мне что-то не хватает, потому что это просто не имеет смысла для меня.
Имейте в виду, что эта вторая ошибка появляется только в случае этого преобразования. В любом месте в фактическом коде появляется ошибка (хотя есть еще много параметров шаблона auto
не-типа).
На данный момент у меня есть некоторые вопросы:
- Что вызывает ошибку в случае компилятора clang?
- Какой из них правильный, в соответствии со стандартом?
Ответы
Ответ 1
Это ошибка clang. Здесь короткое воспроизведение:
template <int A>
struct X {
template <auto B>
X<B> foo();
};
template <int A>
template <auto B>
X<B> X<A>::foo() {
return {};
}
Если auto B
заменяется на int B
, clang принимает его. gcc принимает его как есть. Для clang это только проблема с вложенными объявлениями template
. Нет ничего о auto
в качестве параметра шаблона шаблона-заполнителя, который не позволял бы ему использовать что-то вне линии.
При подаче новой ошибки clang я нашел 35655 с еще более коротким воспроизведением:
template<typename>
struct S {
template<auto n>
static void f() {
+n;
}
};
который терпит неудачу:
source.cpp:5:3: error: invalid argument type 'auto' to unary expression
+n;