Специализированная функция шаблона с удаленным "общим" случаем не может скомпилироваться с g++ <= 4.8.0 и clang++

Компиляция проекта с более старой версией g++ (4.8.0, MinGW) Я обнаружил, что этот код не скомпилирован:

template<typename T>
void foo() = delete;

template<>
void foo<int>(){}

int main() {
    foo<int>();
    return 0;
}

Кажется, что g++ даже не пытается искать явные специализации, если видит, что базовый случай удален.

[email protected]:~/scratch$ /opt/mingw32-dw2/bin/i686-w64-mingw32-g++ -std=c++11 buggy_deleted_template.cpp 
buggy_deleted_template.cpp: In function 'int main()':
buggy_deleted_template.cpp:8:14: error: use of deleted function 'void foo() [with T = int]'
     foo<int>();
              ^
buggy_deleted_template.cpp:5:6: error: declared here
 void foo<int>(){}
      ^
[email protected]:~/scratch$ /opt/mingw32-dw2/bin/i686-w64-mingw32-g++ --version 
i686-w64-mingw32-g++ (rubenvb-4.8.0) 4.8.0
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Вместо этого g++ 4.8.4 и 5.2 (на Linux) не жалуются. Является ли это ошибкой в ​​старой версии компилятора или серой области в стандарте?


Добавление

clang 3.4.1 тоже кажется не нравится:

[email protected]:~/scratch$ clang++ -std=c++11 buggy_deleted_template.cpp                                                             
buggy_deleted_template.cpp:5:6: error: redefinition of 'foo'                                                                         
void foo<int>(){}
     ^
buggy_deleted_template.cpp:5:6: note: previous definition is here
buggy_deleted_template.cpp:8:5: error: no matching function for call to 'foo'
    foo<int>();
    ^~~~~~~~
buggy_deleted_template.cpp:2:6: note: candidate template ignored: substitution failure [with T = int]
void foo() = delete;
     ^
2 errors generated.
[email protected]:~/scratch$ clang++ --version
Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
Target: x86_64-pc-linux-gnu
Thread model: posix

(и @Baum mit Augen в комментариях сообщает, что он все еще не работает в версии 3.7)

Ответы

Ответ 1

Я не знаю, будет ли следующее просветление, но я нашел отчет о дефекте 941: Явная специализация шаблона удаленных функций со статусом C + +11, в котором указано следующее (Emphasis Mine):

Согласно пункту 14.7.3 [temp.expl.spec], только не удаленные шаблоны функций могут быть явно специализированными. Там нет представляется, что это настоятельная необходимость в этом ограничении, и это может быть полезно запретить использование неявно-инстанцированных специализациям, все еще позволяя использовать явно специализированные версии.

Предлагаемое решение (февраль 2010 г.):

Измените 14.7.3 [temp.expl.spec] пункт 1 следующим образом:

Явная специализация любого из следующего:

не удаленный шаблон функции

шаблон класса

не удаленная функция-член шаблона класса

статический элемент данных шаблона класса

класс-член шаблона класса

шаблон класса участника шаблона класса или класса

не удаленный шаблон функции-члена класса или класса шаблон

может быть объявлен...

Теперь текущее состояние черновика N4527 составляет 14.7.3. Явная специализация [temp.expl.spec]:

1 Явная специализация любого из следующих:

(1.1) - шаблон функции

(1.2) - шаблон класса

(1.3) - шаблон переменной

(1.4) - функция-член шаблона класса

(1.5) - статический элемент данных шаблона класса

(1.6) - класс-член шаблона класса

(1.7) - перечисление членов шаблона класса

(1.8) - шаблон класса участника шаблона класса или класса

(1.9) - шаблон функции-члена шаблона класса или класса

...

Итак, я думаю:

template<typename T>
void foo() = delete;

template<>
void foo<int>(){}

int main() {
    foo<int>();
    return 0;
}

Является стандартным совместимым кодом С++ 11 и должен быть принят.