Аргумент по умолчанию для специализации шаблонной функции
template <typename T> void function(T arg1,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max())
{
}
template <> void function<int>(int arg1, int min,int max)
{
}
int main(int argc,char* argv[])
{
function<int>(1);
}
это дает синтаксическую ошибку C2689 и C2059 в строке аргумента функции по умолчанию на ::
маркер. но без специализации все нормально. и если я изменю аргумент по умолчанию и все еще занимаюсь специализацией:
template <typename T> void function(T arg1,
T min = T(0),
T max = T(1))
{
}
template <> void function<int>(int arg1, int min,int max)
{
}
проблема ушла тоже.
Теперь, если я использую это так: function<int>(1,2,3);
или же function<float>(1.0f)
Это нормально, поэтому кажется, что если шаблонная функция специализирована, мы должны переписать аргумент по умолчанию при ее вызове?
но в моем втором случае, где я заменяю std::numeric_limits<T>::..
с T(..)
нет синтаксической ошибки при вызове function<int>(1)
, это почему?
(Я использую Visual Studio 2010 x64)
Поскольку исходная проблема связана с ошибкой, теперь вопрос изменился на то, как ее обойти?
3 ответа
В коде нет ничего плохого; Comeau Online, Intel C++ 11.1 и g++ 4.1.2 успешно его компилируют.
Я предполагаю, что это ошибка в компиляторе. Недавно я представил связанный, но немного другой отчет об ошибке в компиляторе Visual C++ 2010.
В качестве обходного пути вы можете обернуть вызовы:
template <typename T>
T get_limits_min() { return std::numeric_limits<T>::min(); }
template <typename T>
T get_limits_max() { return std::numeric_limits<T>::max(); }
template <typename T> void function(T arg1,
T min = get_limits_min<T>(),
T max = get_limits_max<T>())
{
}
Гадкий? Довольно.
В ответ на сообщение об ошибке, обнаруженной вами в Microsoft Connect, я опубликовал следующее :
Основной шаблон должен иметь параметр со значением аргумента по умолчанию. Значение аргумента по умолчанию должно быть функцией-членом шаблона класса, не входящего в глобальное пространство имен.
Ниже приведен минимальный код для воспроизведения:
namespace N
{
template <typename T>
struct S
{
static T g() { return T(); }
};
}
template <typename T> void f(T = N::S<T>::g()) { }
template <> void f<>(int) { }
int main()
{
f<int>();
}
Компилятор выдает следующие ошибки, обе в строке, где определен основной шаблон:
error C2589: '::' : illegal token on right side of '::'
error C2059: syntax error : '::'
Интересно, что есть еще одна проблема, если шаблон класса находится в глобальном пространстве имен. Учитывая следующий код:
template <typename T>
struct S
{
static T g() { return T(); }
};
template <typename T> void f(T = ::S<T>::g()) { }
template <> void f<>(int) { }
int main()
{
f<int>();
}
Компилятор выдает следующую ошибку в строке, в которой определен основной шаблон:
error C2064: term does not evaluate to a function taking 0 arguments
Оба этих примера тестовых примеров представляют собой правильно сформированные программы на C++.
Как ответили здесь по адресу /questions/8190796/preduprezhdenie-c4003-i-oshibki-c2589-i-c2059-na-x-std-numericlimitsint-max/8190824#8190824 и /questions/9649784/sintaksicheskaya-oshibka-s-stdnumericlimitsmax/9649799#9649799, это связано с минимальным и максимальным макросом, определенным в заголовке окна. Следующий код должен работать, предотвращая расширение макроса:
template <typename T> void function(T arg1,
T min = (std::numeric_limits<T>::min)(),
T max = (std::numeric_limits<T>::max)())
{
}
template <> void function<int>(int arg1, int min,int max)
{
}
int main(int argc,char* argv[])
{
function<int>(1);
}
Он успешно скомпилирован... в Comeau Online, http://codepad.org,EDG, EDG Compiler и G++ .