Аргумент по умолчанию для специализации шаблонной функции

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++ .

Другие вопросы по тегам