Primero tengo una plantilla de función

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

Entonces quiero proporcionar implementaciones especializadas dado que S es un contenedor STL. Especialmente, quiero proporcionar diferentes argumentos predeterminados.

Dado que la especialización de plantilla de función parcial no está permitida en C ++, simplemente sobrecargo foo. Decir

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

Todo muy bien en este punto.

Ahora quiero escribir una plantilla de función partial_foo, que acepta solo un parámetro double b = 6, y luego dejar que el compilador decida el argumento predeterminado para a, dependiendo de qué versión de foo llama. Tenga en cuenta que b está después de a en la firma de llamada de foo.

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

Idealmente, foo_partial(int) tendría un argumento predeterminado int a = 1 mientras que foo_partial(vector<int>()) tendría un argumento predeterminado int a = 3.

Mi pregunta es: ¿Puedo hacer esto (es decir, cómo implementar foo_partial) o hay alguna solución, dado el diseño de foo?

Para un ejemplo concreto, considere

#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>());
}

La salida es

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

Mi pregunta es equivalente a: ¿Hay algo o alguna solución alternativa que pueda hacer con el diseño de foo_partial para que el resultado sea

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

Gracias por su tiempo!

0
aafulei 17 oct. 2018 a las 09:35

2 respuestas

La mejor respuesta

No incluya #include <bits/stdc++.h>, no es estándar y no funciona en la mayoría de las plataformas.

using namespace std tampoco se recomienda ya que puede causar conflictos entre futuras adiciones estándar y su propio código.

Una forma de resolver su problema sería mover sus argumentos predeterminados a una clase de plantilla con especializaciones:

#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>());
}

Si solo se está especializando foo para cambiar los argumentos predeterminados, las sobrecargas de funciones ya no son necesarias.

2
Alan Birtles 17 oct. 2018 a las 07:04

También puede emplear el lenguaje de parámetros con nombre , que es más genérico y escalable:

#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>{});
}

Que imprime:

foo(T) with a = 1 and b = 6    
foo(std::vector<T>) with a = 3 and b = 6
0
Daniel Langr 17 oct. 2018 a las 07:22