Именом конструктора и шаблоны? - PullRequest
5 голосов
/ 11 марта 2011

Есть ли способ использовать именованный конструктор Idiom с шаблонами "довольно"?

Например:

#include <vector>
using namespace std;

template< typename T >
class Foo
{
public:
    static Foo Copy(const T& arg)
    {
        Foo ret;
        ret.t_copy = arg;
        return ret;
    }

    static Foo CopyClear(const T& arg)
    {
        Foo ret;
        ret.t_copy = arg;
        ret.t_copy.clear();
        return ret;
    }

private:
    T t_copy;
};


int main( int argc, char** argv )
{
    vector<double> vec;
    vec.push_back(1);

    // #1: won't compile
    Foo< vector<double> > a_foo = Foo::CopyClear( vec );

    // #2: ugly, but works
    Foo< vector<double> > a_foo = Foo< vector<double> >::CopyClear( vec );

    return 0;
}

Я бы хотелиспользовать синтаксис #1 как-то.#2 работает, но потирает СУХОЙ чувствую неправильно.

РЕДАКТИРОВАТЬ: Новая, более "реалистичная" версия Foo.

РЕДАКТИРОВАТЬ 2: Нет C ++ 0x / C ++ 1x для меня боюсь: (

Ответы [ 6 ]

3 голосов
/ 11 марта 2011

Технически это нормально и, возможно, самый простой ответ на ваш конец вопрос:

    Foo< vector<double> > a_foo = a_foo.CopyClear( vec );

Это технически ОК, потому что CopyClear - это static функция-член.

И никаких технических проблем нет, например, вместо этого вы можете использовать typedef.Или просто поместите эти static функции-члены в область имен, как шаблоны функций.Или в каком-то классе помощников, как кто-то уже предлагал.

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

Например, в CopyClear, почему вы копируете вектор, а затем отбрасываете результат копирования ?Вам нужно только создать пустой вектор того типа, который знает ваш код.

И, например, почему вы вводите механизм побочных эффектов?

Следует избегать и устранять побочные эффекты, не введено.

Приветствия и hth.,

3 голосов
/ 11 марта 2011

В дополнение к ответу @ Jon см. std::make_pair и его отношение к std::pair, если вам нужен сам класс в качестве шаблона.

3 голосов
/ 11 марта 2011

Я не думаю, что есть СУХАЯ проблема, думайте об этом как об ограничении языка. Если у вас есть Class Foo без шаблона, но вы хотите создать новый объект из статического метода, вам нужно сделать что-то вроде:

Foo a_foo = Foo::HalfSize(something);

и, конечно, Фу повторяется дважды.

Итак, поскольку здесь полное имя класса Foo< vector<double> >, логично получить статический метод из Foo< vector<double> >::HalfSize(), поскольку это путь C ++.

3 голосов
/ 11 марта 2011

Обновленный ответ

Если я правильно понимаю ваши намерения, это поможет:

template< typename T >
class Foo
{
private:
    friend class FooHelper;
    size_t sz;
};

class FooHelper
{
public:
    template< typename T >
    static Foo<T> Size(const T& arg)
    {
        Foo<T> ret;
        ret.sz = arg.size();
        return ret;
    }

    template< typename T >
    static Foo<T> HalfSize(const T& arg)
    {
        Foo<T> ret;
        ret.sz = arg.size() / 2;
        return ret;
    }
};

Затем компилируется:

int main( int argc, char** argv )
{
    vector<double> vec;
    vec.push_back(1);

    Foo<vector<double>> a_foo = FooHelper::HalfSize( vec );
}
2 голосов
/ 11 марта 2011

C ++ 1x на помощь:

auto a_foo = Foo::HalfSize<vector<double>>( vec );

И, да, два закрывающих >> анализируются как > > в C ++ 1x.

Возможно, уже доступен с компилятором рядом с вами.

2 голосов
/ 11 марта 2011

Если вы можете использовать функции C ++ 0x, ключевое слово auto поможет. Есть ли причина, по которой Size() и HalfSize() должны быть статическими методами? Если вы предоставляете методы для мутации sz, вы можете сделать это:

template<class T>
Foo<T> HalfSize(const T& arg)
{
    Foo<T> ret;
    ret.setSz(arg.size() / 2); // or similar
    return ret;
}

и затем # 1 немного более достижимо.

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