Я могу воспроизвести эту ошибку только в G CC до версии 8. Различие в поведении связано с тем, что спецификатор noexcept
является частью типа функции в версии C ++ 14 для G CC 7 (но не Clang's), хотя это особенность C ++ 17. Это можно увидеть, если добавить частичные специализации is_noexcept_callable
:
template <class... Args>
struct is_noexcept_callable<int(&)(int), Args...>
: public std::false_type {};
template <class... Args>
struct is_noexcept_callable<int(int), Args...>
: public std::false_type {};
Это внезапно приводит к двум false
s : G CC сохраняет атрибут noexcept
в функции типов, но в явном виде игнорирует их во время вывода аргумента шаблона , так что вышеупомянутые специализации выбраны, несмотря на сообщения об ошибках, показывающие noexcept
, если мы удалим определения:
prog.cc:30:5: note: template argument deduction/substitution failed:
prog.cc:28:22: error: incomplete type 'is_noexcept_callable<int (&)(int) noexcept, int>' used in nested name specifier
Почему влияет ли определение TESTREF
на is_noexcept_callable
?
Вторая часть вашего вопроса более тонкая. Здесь проблема в том, что is_noexcept_callable
уже создан с соответствующим типом int(int) [noexcept]
, прежде чем использовать его в main
, но к нему не прикреплено ничего, кроме того, что результат is_noexcept_callable<int(int), int>::value
фиксируется в true.
decltype(id)
- это int(int) [noexcept]
, где [noexcept]
- мое обозначение переходной спецификации исключений express G CC, прикрепленной к типу функции. Таким образом, evalInt(1,id)
вызывает создание экземпляров
is_noexcept_callable<F,int>
, где F = int(&)(int) [noexcept]
при TESTREF = X&&
и F = int(int) [noexcept]
при TESTREF = X const&
Таким образом, когда вы отключаете первую ветвь своей директивы if, is_noexcept_callable<int(int),int>::value == true
удерживается после обработки noexcept(evalInt(1,id))
, потому что id
не исключает, и это распространяется по цепочке создания .
Следовательно, следующее печатает две ложные:
int main(int argc, char* argv[])
{
std::cout << std::boolalpha
<< noexcept(evalInt(1,thrower))
<< std::endl;
std::cout << std::boolalpha
<< is_noexcept_callable<decltype(thrower), int>::value
<< std::endl;
}
Демонстрация: https://wandbox.org/permlink/YXDYfXwtEwMQkryD