Определение разных аргументов по умолчанию для разных версий шаблонов функций - PullRequest
0 голосов
/ 17 октября 2018

Сначала у меня есть шаблон функции

template<typename S>
void foo(const S & s, int a = 1, double b = 2)

Затем я хочу предоставить специализированные реализации, поскольку S является контейнером STL.Специально, я хочу предоставить разные аргументы по умолчанию.

Так как частичная специализация шаблона функции не разрешена в C ++, я просто перегружаю foo.Скажем

template<typename T>
void foo(const vector<T> & s, int a = 3, double b = 4)

Все хорошо на этом этапе.

Теперь я хочу написать шаблон функции partial_foo, который принимает только один параметр double b = 6, а затем позволить компилятору решитьаргумент по умолчанию для a, в зависимости от того, какую версию foo он вызывает. Обратите внимание, что b следует после a в сигнатуре вызова foo.

template<typename S>
foo_partial(const S & s, double b = 6)

В идеале foo_partial(int) будет иметь аргумент по умолчанию int a = 1, в то время как foo_partial(vector<int>()) будет иметь аргумент по умолчанию int a = 3.

Мой вопрос: могу ли я сделать это (то есть, как реализовать foo_partial), или есть ли обходной путь, учитывая дизайн foo?

Для конкретного примера, пожалуйста, рассмотрите

#include <bits/stdc++.h>
using namespace std;

template<typename S>
void foo(const S & s, int a = 1, double b = 2)
{
    printf("foo(S) with a = %d, b = %.0f\n", a, b);
}

template<typename T>
void foo(const vector<T> & t, int a = 3, double b = 4)
{
    printf("foo(vector<T>) with a = %d, b = %.0f\n", a, b);
}

template<typename S>
void foo_partial(const S & s, double b = 6)
{
    // how to implement foo_partial so that ____ corresponds to
    // the default argument in the proper version of foo?
    int ____ = 5;
    foo(s, ____, b);
}

int main()
{
    foo_partial(0);
    foo_partial(vector<int>());
}

Вывод

foo(S) with a = 5, b = 6
foo(vector<T>) with a = 5, b = 6

Мой вопрос эквивалентен: есть ли что-нибудьили любой обходной путь, который я могу сделать с дизайном foo_partial, чтобы вывод был

foo(vector) with a = 1, b = 6
foo(forward_list) with a = 3, b = 6

Спасибо за ваше время!

Ответы [ 2 ]

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

Вы также можете использовать так называемый именованный параметр идиома , который является более общим и масштабируемым:

#include <iostream>
#include <vector>

template <typename T> class Foo {
  int a_; double b_; const T& value_;
public:
  Foo(const T& value) : value_(value), a_(1), b_(2.0) { }
  Foo& set_a(int a) { a_ = a; return *this; }
  Foo& set_b(double b) { b_ = b; return *this; }
  void operator()() { std::cout << "foo(T) with a = " << a_ << " and b = " << b_ << std::endl; }
};

template <typename T> class Foo<std::vector<T>> {
  int a_; double b_; const std::vector<T>& value_;
public:
  Foo(const std::vector<T>& value) : value_(value), a_(3), b_(4.0) { }
  Foo& set_a(int a) { a_ = a; return *this; }
  Foo& set_b(double b) { b_ = b; return *this; }
  void operator()() { std::cout << "foo(std::vector<T>) with a = " << a_ << " and b = " << b_ << std::endl; }
};

template <typename T>
void foo_partial(const T& value, double b = 6) { Foo<T>(value).set_b(b)(); }

int main() {
  foo_partial(0);
  foo_partial(std::vector<int>{});
}

, который печатает:

foo(T) with a = 1 and b = 6    
foo(std::vector<T>) with a = 3 and b = 6
0 голосов
/ 17 октября 2018

Не включайте #include <bits/stdc++.h>, это нестандартно и не будет работать на большинстве платформ.

using namespace std также не рекомендуется, поскольку это может вызвать конфликты между будущими стандартными дополнениями и вашим собственным кодом.

Один из способов решения вашей проблемы - переместить аргументы по умолчанию в класс шаблона со специализациями:

#include <vector>
#include <cstdio>

using std::vector;

template <typename S>
struct defaults
{
    static constexpr int a = 1;
    static constexpr double b = 2;
};

template <typename T>
struct defaults<vector<T>>
{
    static constexpr int a = 3;
    static constexpr double b = 4;
};

template<typename S>
void foo(const S & s, int a = defaults<S>::a, double b = defaults<S>::b)
{
    printf("foo(S) with a = %d, b = %.0f\n", a, b);
}

template<typename T>
void foo(const vector<T> & t, int a = defaults<vector<T>>::a, double b = defaults<vector<T>>::b)
{
    printf("foo(vector<T>) with a = %d, b = %.0f\n", a, b);
}

template<typename S>
void foo_partial(const S & s, double b = 6)
{
    foo(s, defaults<S>::a, b);
}

int main()
{
    foo_partial(0);
    foo_partial(vector<int>());
}

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

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