Ответ 1
Это ошибка gcc 57891. Преобразование интегральной константы 42
в bool
включает сужение преобразования, которое не допускается в аргументах шаблона, отличных от типа. Следовательно, enable_if
плохо сформирован, а специализация pick
должна быть отброшена, как правильно делает clang.
§14.3.2/5 [temp.arg.nontype]
Следующие преобразования выполняются для каждого выражения, используемого в качестве non-type template-argument. Если аргумент шаблона не-типа не может быть преобразуется в тип соответствующего шаблона-параметра, тогда программа плохо сформирована.
- для шаблона-шаблона, не относящегося к типу интегральный или перечисляемый тип, конверсии, разрешенные в преобразованном постоянное выражение (5.19)....
§5.19/3 [expr.const]
...
A преобразованное константное выражение типаT
является выражением, неявно преобразованным в prvalue типаT
, где преобразованное выражение является ядром константное выражение и неявная последовательность преобразований содержат только определенные пользователем преобразования, преобразования lvalue-to-rvalue (4.1), интегральные продвижения (4.5) и интегральные преобразования (4.7) , кроме сужения конверсий (8.5.4).
§8.5.4/7 [dcl.init.list]
Сужение преобразования является неявным преобразованием
...
- от целочисленного типа или типа неперечисленного перечисления до целочисленного типа, который не может представлять все значения исходного типа, за исключением случаев, когда источником является постоянное выражение, значение которого после того, как целые акции будут вписываться в целевой тип.
Этот минимальный пример демонстрирует ошибку gcc:
template<bool>
struct foo{};
foo<10> f;
int main() {}
gcc-4.9 принимает код, в то время как clang-3.4 отклоняет его со следующей ошибкой:
ошибка: аргумент шаблона не-типа оценивается до 10, который не может быть сужен, чтобы набрать 'bool' [-WС++ 11-сужение]
foo<10> f; ^
Исправить вашу конкретную проблему легко. Убедитесь, что аргумент шаблона непигового типа enable_if
оценивается как bool
template<class T>
struct pick<T, typename std::enable_if< is_nice<T>::value != 0 >::type >
// ^^^^^^
{
typedef std::integral_constant<int, is_nice<T>::value > type;
};