[temp.over.link] / 6 указывает, когда шаблон двух функций объявления - это перегрузки. Это делается путем определения эквивалентности двух шаблонов функций следующим образом:
Два шаблона функций являются эквивалентными, если они [..] имеют возвращаемые типы [..], которые эквивалентны с использованием описанных выше правил для сравнения выражений, включающих параметры шаблона.
"Правила, описанные выше"
Два выражения, включающие параметры шаблона, считаются эквивалентными, если два определения функции, содержащие эти выражения, удовлетворяют одному правилу определения (3.2) [..]
ODR, относящееся к этой части, указано в [basic.def.odr] / 6 это
Если такая сущность с именем D
определена более чем в одной единице перевода, тогда
- каждое определение
D
должно состоять из одной и той же последовательности токенов;
Очевидно, что в качестве возвращаемых типов (которые являются конечными возвращаемыми типами согласно [dcl.fct] / 2) не состоят из одних и тех же токенов, два определения функции, содержащие эти выражения, нарушили бы ODR.
Следовательно, объявления foo
объявляют неэквивалентные шаблоны функций и перегружают имя.
Ошибка, которую вы видите, возникает из-за отсутствия поддержки VC ++ для выражения SFINAE - предположительно, конечные возвращаемые типы не проверяются на эквивалентность.
Обходной путь
Сделать шаблоны функций неэквивалентными можно другим способом - изменить список параметров шаблона. Если переписать второе определение так:
template <typename F, int=0>
auto foo(F&& f) -> decltype(f(0, 1), void())
{
std::cout << "2" << std::endl;
}
Затем VC ++ компилирует его нормально. Я сократил цитату в [temp.over.link] / 6, в которой говорится об этом:
Два шаблона функций эквивалентны, если они объявлены в одной области действия, имеют одинаковое имя, имеют одинаковые списки параметров шаблона [..]
Фактически, чтобы иметь возможность легко вводить новые перегрузки, вы можете использовать небольшой помощник:
template <int I>
using overload = std::integral_constant<int, I>*;
Использование, например,
// Remember to separate > and = with whitespace
template <typename... F, overload<0> = nullptr>
auto foo(F&&... f) -> decltype(f(0, 1)..., void())
template <typename... F, overload<1> = nullptr>
auto foo(F&&... f) -> decltype(f(0, 1, 2)..., void())
Демо.
person
Columbo
schedule
28.01.2015
, typename = void
ко второмуfoo
может привести к компиляции MSVC2015 Preview. - person jingyu9575   schedule 29.01.2015