2015-08-29 2 views
1

Код ниже компилируется и работает отлично с MSVC 2013, но не clang ++ 3.6. Какой компилятор прав?Ошибка шаблона Variadic - MSVS2013 компилирует, clang-3.5 не

MSVC 2013 компилирует и выполняет код, печать 26,04:

#include <iostream> 

template <typename T, typename ... U> 
auto mul(T t, U ... u) -> decltype(t * mul(u ...)) 
{ 
    return t * mul(u ...); 
} 

template <typename T> 
T mul(T t) { return t; } 

int main() 
{ 
    std::cout << mul(2., 3.1, 4.2) << std::endl; 
} 

Однако компиляция с лязгом ++ - 3.6 Урожайность ошибки:

$ clang++ test.cpp -stdlib=libc++ -Wall -Wextra -std=c++14 
prog.cc:14:15: error: no matching function for call to 'mul' 
     std::cout << mul(2., 3.1, 4.2) << std::endl; 
        ^~~ 
prog.cc:4:6: note: candidate template ignored: substitution failure [with T = double, U = <double, double>]: use of undeclared identifier 'mul' 
auto mul(T t, U ... u) -> decltype(t * mul(u ...)) 
    ^        ~~~ 
prog.cc:10:3: note: candidate function template not viable: requires single argument 't', but 3 arguments were provided 
T mul(T t) { return t; } 
^
1 error generated. 

Является ли заявление о мул не доступен определить возвращаемый typedecl?

ответ

1

Вы пытаетесь определить тип возврата mul с точки зрения типа возврата mul. Точнее, вы используете mul в выражении decltype, прежде чем он будет полностью объявлен (что точно говорит об ошибке компилятора).
Шаблонный экземпляр MSVC работает нестандартно, поэтому я считаю, что clang является правильным - однако он может быть реализован, но я так не думаю (возможно, кто-то знает соответствующую часть стандарта).

1

Во-первых, если вы замените свой вызов на main на mul(2., 3.1) (два аргумента), код еще не будет компилироваться в Clang и GCC. Но в этом случае он не будет компилироваться просто потому, что ваш единственный аргумент mul объявлен после версии с несколькими аргументами. Версия с одним аргументом пока не известна в момент объявления версии с несколькими аргументами. Если вы переместите объявление с одним аргументом в начало, будет скомпилирован вызов mul(2., 3.1). Он компилируется, потому что спецификация возвращаемого типа decltype(t * mul(u ...)) относится к уже полностью объявленной версии с одним аргументом mul.

Во-вторых, первоначальный вызов с тремя аргументами mul(2., 3.1, 4.2) не компилируется, поскольку он пытается рекурсивно объявить свой тип возврата через себя (через версию с двумя аргументами, которая по-прежнему относится к одному и тому же шаблону). Это запрещено. Да, мы все знаем, что рекурсия четко определена и в конечном итоге заканчивается, но язык этого не позволяет. (Все еще ищет официальную цитату ...)

Смежные вопросы