неоднозначная перегрузка шаблона для параметра шаблона является контейнером - PullRequest
3 голосов
/ 18 октября 2011

Пожалуйста, рассмотрите следующий пример:

#include <string>
#include <vector>

using std::string;
using std::vector;

template <typename T>
const T GetValue()
{
    return T(); // some value
}

template <typename T>
const vector<T> GetValue()
{
    return vector<T>(); // some vector of values
}

int main(int argc, char* argv[])
{
    int i = GetValue<int>();
    vector<int> = GetValue<vector<int>>();
    return 0;
}

У меня есть две функции шаблона, которые должны анализировать значения из некоторого хранилища в зависимости от заданного типа. Первый должен выполнять работу для простых типов данных, второй - только для векторов простых типов данных. Моя проблема в том, что сопоставление шаблонов неоднозначно, поскольку T может быть vector<T>. Интересно, как правильно реализовать перегрузку / специализацию для векторных типов.

Любая помощь будет принята с благодарностью!

Ответы [ 4 ]

6 голосов
/ 18 октября 2011

Одним простым способом является использование out-param, так что параметр шаблона может быть выведен из аргумента:

#include <vector>
using std::vector;

template <typename T>
void GetValue(T &t)
{
    t = T(); // some value
}

template <typename T>
void GetValue(vector<T> &v)
{
    v = vector<T>(); // some vector of values
}

int main(int argc, char* argv[])
{
    int i;
    GetValue(i);
    vector<int> v;
    GetValue(v);
    return 0;
}

GetValue(v) не является неоднозначным, поскольку правила вывода аргумента шаблона говорятчто вторая перегрузка лучше подходит.

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

#include <vector>
using std::vector;

template <typename T>
struct Getter {
    T get(void) {
        return T(); // some value
    }
};

template <typename T>
struct Getter<vector<T> > {
    vector<T> get(void) {
        return vector<T>(); // some vector of values
    }
};

template <typename T>
T GetValue(void)
{
    return Getter<T>().get();
}

int main(int argc, char* argv[])
{
    int i = GetValue<int>();
    vector<int> v = GetValue<vector<int> >();
    return 0;
}
4 голосов
/ 18 октября 2011

Обе версии GetValue отличаются только типом возврата, поэтому это не перегрузка.

Я бы предложил вам иметь только один GetValue, а затем реализовать две функции, которые отличаются типом параметра , в отличие от , вернуть тип, и переадресовать вызов как:

namespace details
{
       template <typename T>
       T  FillValue(T*)
       {
          //your code
       }

       template <typename T>
       vector<T> FillValue(vector<T> *)
       {
           //your code 
       }
}

template <typename T>
T GetValue()
{
    return details::FillValue((T*)0); //pass null pointer of type T*
}

Правильный FillValue будет выбран компилятором на основе типа аргумента, переданного функции, который равен T*. Если T равно vector<U> для некоторого типа U, будет выбрана вторая функция, в противном случае будет выбрана первая функция.

1 голос
/ 18 октября 2011

Поместите общий метод в class (с именем GetValue предпочтительно) и объявите этот метод как operator T(). Теперь специализируйте class для vector<T>:

template <typename T>
struct GetValue
{
  operator const T () const
  {
    std::cout<<"GetValue()\n";
    return T(); // some value
  }
};

template <typename T>
struct GetValue<vector<T> >
{
  operator const vector<T> ()
  {
    std::cout<<"GetValue<vector<T>>()\n";
    return vector<T>(); // some vector of values
  }
};

Использование:

int i = GetValue<int>();
vector<int> v = GetValue<vector<int> >();

Демо

1 голос
/ 18 октября 2011

Вы можете переместить частичную специализацию в вспомогательный класс:

#include <vector>

template <typename T>
class Creator {
public:
    T operator()() const { return T(); }
};

template <typename T>
class Creator<std::vector<T> > {
public:
    std::vector<T> operator()() const { return std::vector<T>(); }
};

template <typename T>
T GetValue() {
    return Creator<T>()();
}

int main() {
    int i = GetValue<int>();
    std::vector<char> v = GetValue<std::vector<char> >();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...