Почему этот вывод аргумента шаблона завершается неудачно, если задано значение по умолчанию? - PullRequest
0 голосов
/ 30 октября 2018

работает следующий код:

template <typename T>
struct Foo
{
    template <typename OStream>
    static void default_print_function(OStream &, const T &);

    template <typename OStream, typename PrintFunction>
    void print(
        OStream &,
        const PrintFunction & = &Foo<T>::default_print_function<OStream>) const;

    template <typename OStream>
    void print(OStream &) const;
};


template <typename T>
template <typename OStream>
void Foo<T>::default_print_function(OStream & o, const T & value)
{
    o << value;
}

template <typename T>
template <typename OStream, typename PrintFunction>
void Foo<T>::print(OStream & o, const PrintFunction & f)
const
{
    T test_value = 123;

    o << "TEST: ";
    f(o, test_value);
}

template <typename T>
template <typename OStream>
void Foo<T>::print(OStream & o)
const
{
    print(o, &default_print_function <OStream>);
}

#include <iostream>

int main()
{
    Foo <int> foo;

    foo.print(std::cerr, &Foo<int>::default_print_function<std::ostream>);
    std::cerr << std::endl;

    foo.print(std::cerr);
    std::cerr << std::endl;
}

Однако, если я закомментирую перегрузку void print (OStream &) const:

template <typename T>
struct Foo
{
    template <typename OStream>
    static void default_print_function(OStream &, const T &);

    template <typename OStream, typename PrintFunction>
    void print(
        OStream &,
        const PrintFunction & = &Foo<T>::default_print_function<OStream>) const;

    template <typename OStream>
    void print(OStream &) const;
};


template <typename T>
template <typename OStream>
void Foo<T>::default_print_function(OStream & o, const T & value)
{
    o << value;
}

template <typename T>
template <typename OStream, typename PrintFunction>
void Foo<T>::print(OStream & o, const PrintFunction & f)
const
{
    T test_value = 123;

    o << "TEST: ";
    f(o, test_value);
}

/*template <typename T>
template <typename OStream>
void Foo<T>::print(OStream & o)
const
{
    print(o, &default_print_function <OStream>);
}*/

#include <iostream>

int main()
{
    Foo <int> foo;

    foo.print(std::cerr, &Foo<int>::default_print_function<std::ostream>);
    std::cerr << std::endl;

    foo.print(std::cerr);
    std::cerr << std::endl;
}

Тогда он не скомпилируется:

test.cpp: In function ‘int main()’:
test.cpp:54:25: error: no matching function for call to ‘Foo<int>::print(std::ostream&)’
  foo .print (std :: cerr);
                         ^
test.cpp:8:7: note: candidate: template<class OStream, class PrintFunction> void Foo<T>::print(OStream&, const PrintFunction&) const [with OStream = OStream; PrintFunction = PrintFunction; T = int]
  void print (
       ^~~~~
test.cpp:8:7: note:   template argument deduction/substitution failed:
test.cpp:54:25: note:   couldn't deduce template parameter ‘PrintFunction’
  foo .print (std :: cerr);

Значение по умолчанию для второго аргумента для print написано так, что, как мне кажется, точно эквивалентно тому, как оно пишется при первом вызове в функции main.

foo .print (std :: cerr, & Foo <int> :: default_print_function <std :: ostream>);

Так почему аргумент шаблона может быть выведен в этом вызове, но не может быть выведен в аргументе по умолчанию

const PrintFunction & = & Foo <T> :: default_print_function <OStream>

1 Ответ

0 голосов
/ 30 октября 2018

Это не выводимый контекст:

cppreference

Не выведенные контексты:

...

4) Параметр шаблона, используемый в типе параметра функции параметр, который имеет аргумент по умолчанию, который используется в вызове для какого аргумента производится удержание

РЕДАКТИРОВАТЬ (почему это не выводимый контекст)

Поскольку у невыгруженного контекста есть преимущество: он позволяет использовать тип, если его можно получить из других источников.

Рассмотрим этот пример:

template<class T>
void foo(T, T = 1.0) {};

int main() {
    foo(2);
}

Это действительный код. Но если бы это был не выводимый контекст, вычет был бы конфликтным. Несколько разумно предположить, что программист хочет выполнить преобразование вместо сбоя.

С другой стороны, тип по существу дается в другом месте (аргумент по умолчанию, который дается при объявлении). Например, ваш код будет в порядке, если вы decltype в параметре шаблона:

template <typename OStream, typename PrintFunction = decltype(&Foo<T>::default_print_function<OStream>)>

В общем, мы ничего не теряем, чтобы сделать его не выводимым контекстом. Более того, мы делаем возможным преобразование типа аргумента по умолчанию, когда тип предоставляется в другом месте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...