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

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)

поскольку первоначальная проблема возникла из-за ошибки, вопрос теперь изменился на как ее обойти?


person uray    schedule 04.08.2010    source источник


Ответы (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++.

person James McNellis    schedule 04.08.2010

Как указано здесь в https://stackoverflow.com/a/13566433/364084 и https://stackoverflow.com/a/27443191/364084, это связано с минимальным и максимальным макросом, определенным в заголовке Windows. Следующий код должен работать, предотвращая раскрытие макроса:

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);
}
person umbersar    schedule 10.10.2016

Он успешно скомпилирован... в Comeau Online, компиляторе http://codepad.org,EDG и G++. .

person Community    schedule 04.08.2010