Russian Qt Forum
Июнь 11, 2024, 10:39 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Переменное количество аргументов констр  (Прочитано 6807 раз)
ssoft
Гость
« : Июль 22, 2013, 14:31 »

Есть класс (всего лишь пример)

Код
C++ (Qt)
template < typename _Type, int _N >
class Point
{
   _Type m_values[ _N ];
 
   ...
};
 

Как бы его реализовать так, чтобы в коде можно было использовать в виде

Код
C++ (Qt)
 
Point< double, 2 > point2d( 1.0, 2.0 );
Point< double, 3 > point3d( 1.0, 2.0, 3.0 );
 
...
 
Point< double, N > pointNd( 1.0, 2.0, ... , N );
 
 

ну или хотя бы в виде

Код
C++ (Qt)
 
Point< double, 2 > point2d( Something( 1.0, 2.0 ) );
Point< double, 3 > point3d( Something( 1.0, 2.0, 3.0 ) );
 
...
 
Point< double, N > pointNd( Something( 1.0, 2.0, ... , N ) );
 
 

Т.е.,  имеется заранее известное количество аргументов конструктора, равное входящему параметру шаблона _N.

Есть решения, если не использовать вариации типа printf( fmt, ... ) и новый стандарт C++11?

« Последнее редактирование: Июль 22, 2013, 14:38 от ssoft » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #1 : Июль 22, 2013, 14:34 »

С variadic template это можно было бы легко сделать.. Но это c++11 Грустный
 
« Последнее редактирование: Июль 22, 2013, 14:37 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июль 22, 2013, 14:59 »

Код
C++ (Qt)
Point< double, 2 > point2d( 1.0, 2.0 );
Point< double, 3 > point3d( 1.0, 2.0, 3.0 );
 
Понимаю что это "всего лишь пример" - но как Вы запишете метод (или оператор) векторного произведения "в общем виде"? Улыбающийся. А point4d (часто кватернион) отличается еще больше. Др словами хотя обобщение напрашивается - "сущности" разные, возможно стоит удовлетвориться набором индивидуальных классов.
Записан
ssoft
Гость
« Ответ #3 : Июль 22, 2013, 15:07 »

Понимаю что это "всего лишь пример" - но как Вы запишете метод (или оператор) векторного произведения "в общем виде"? Улыбающийся. А point4d (часто кватернион) отличается еще больше. Др словами хотя обобщение напрашивается - "сущности" разные, возможно стоит удовлетвориться набором индивидуальных классов.

Все частности можно определить специализацией шаблонов.
Point - это всего лишь доступный для быстрого понимания пример, где это может быть использовано. Подмигивающий
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #4 : Июль 22, 2013, 22:26 »

Нужно что-то типа такого?

http://ideone.com/yiwPkQ

Код:

#include<iostream>
 
template < class Type, int N >struct Point
{
    template<class ... Args> Point( Args&&... args )
    {
        const Type arr[]={ args... };
       
        enum { SIZE = sizeof(arr)/sizeof(Type) };
       
        static_assert(SIZE<= N, "INVALID_SIZE");
 
        for(size_t n=0;n<SIZE;++n) m_values[n]=arr[n];
        for(size_t n=SIZE;n<N;++n) m_values[n]=0;
    }
 
    void View()const
    {
        std::cout<<"---BEGIN--------------------------\n";
        for(size_t n=0;n<N;++n) std::cout<<n<<") "<<m_values[n]<<'\n';
        std::cout<<"---END----------------------------\n";
    }
    Type m_values[N];
};
 
 
int main()
{
    int v=10;
    Point<int,10> p(1,2,3,4,v);
    p.View();
    return 0;
}

« Последнее редактирование: Июль 22, 2013, 22:39 от _Bers » Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #5 : Июль 23, 2013, 00:12 »

Да, variadic template  как раз для этой ситуации, жаль их только недавно придумали Улыбающийся.

Параметр N наверняка имеет какое-то ограничение (пусть 10 или 20). Можно сделать конструктор с параметрами по умолчанию, а там сколько придет - столько и обрабатывать. Или наплодить N конструкторов на все случаи жизни, при компиляции выберется нужный. В любом случае руками придется много делать.

Еще можно подумать над вариантами со списком типов или какими-нибудь рекурсивными шаблонами. Похоже, без Александреску не обойтись Улыбающийся.
Записан

Пока сам не сделаешь...
ssoft
Гость
« Ответ #6 : Июль 23, 2013, 07:01 »

Да хотелось бы что-то типа такого, как в C++11.

Пока что я использую такой подход

Код
C++ (Qt)
 
template < typename _Type, unsigned int _N >
class Point
{
...
public:
   Point ( const _Type( &values )[ N ] );
...
};
 
 

// Базовый класс, преобразующийся к _Type[ _N ]

Код
C++ (Qt)
 
template < typename _Type, unsigned int _N >
class BasicArgs
{
public:
   typedef _Type ( Values ) [ N ];
 
protected:
   Values m_values;
 
public:
   inline BasicArgs () {}
   inline operator const Values & () const { return m_values; }
...
};
 

// Конкретный класс с дальнейшим уточнением

Код
C++ (Qt)
 
template < typename _Type, unsigned int _N >
class Args;
 
 

// Для одного аргумента

Код
C++ (Qt)
template < typename _Type >
class Args< _Type, 1 >
   : public BasicArgs< _Type, 1 >
{
public:
   inline Args ( const _Type & value = _Type() )
   {
       this->m_values[ 0 ] = value;
   }
};
 

// Для двух аргументов

Код
C++ (Qt)
 
template < typename _Type >
class Args< _Type, 2 >
   : public BasicArgs< _Type, 2 >
{
public:
   inline Args (
       const _Type & value1 = _Type(),
       const _Type & value2 = _Type() )
   {
       this->m_values[ 0 ] = value1;
       this->m_values[ 1 ] = value2;
   }
};
 
 

и т.д. для любого количества, пока не надоест писать  Смеющийся

Тогда в коде можно использовать такую запись

Код
C++ (Qt)
 
typedef Point< double, 3 > Point3d;
typedef Vector< double, 3 > Vector3d;
typedef Args< double, 3 > Args3d;
 
Point3d p1 = Point3d( Args3d( 1.0, 2.0, 3.0 ) );
Point3d p2 = Point3d( Args3d( 4.0, 5.0, 6.0 ) );
...
 
Vector3d v1 = Vector3d( Args3d( 1.0, 1.0, 1.0 ) );
...
 
 

Лучше пока ничего не придумал.
Может у кого есть более изящное решение?
« Последнее редактирование: Июль 23, 2013, 07:06 от ssoft » Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #7 : Июль 23, 2013, 09:12 »

Да хотелось бы что-то типа такого, как в C++11.

Почему бы тогда ни сделать просто: взять с++11 и не мучаться с велосипедами?

Пока что я использую такой подход

Если дизайн устраивает - то нормальный способ. Смысли - он простой. Его легко понять. Если при этом это легко использовать - то чего ещё нужно то?

А вообще, в рамках с++03 нет вариардиков, поэтому там при любой конструкции будет нечто, что будет обладать тучей конструкторов, или тучей перегрузок, или тем и тем одновременно.

Лучше пока ничего не придумал.
Может у кого есть более изящное решение?

Если хочется высокой гибкости, то в рамках 2003 есть несколько способов имитировать вариардики. Все они обладают разной степенью "сложности".

Как вариант вот такой дизайн самодельных кортежей:

Код:
void Foo(int, double, char) { ... }

struct Rabbit
{
    void Foo(int, double, char) { ... }
    void operator()(int, double, char) { ... }

};

my::tuple<int,double,char> t(10,10.0,'a');

t.transmit(&Foo); //эквивалент Foo(10,10.0,'a'); кортеж просто передаст все свои аргументы получателю

...

Rabbit rabbit;
t.transmit(rabbit, &Rabbit::Foo); //эквивалент rabbit.Foo(10,10.0,'a'); кортеж просто передаст все свои аргументы получателю
//здесь rabbit - кому передать
//Rabbit::Foo - функция, получает значения кортежа. Отвечает за логику наполнения данными

...

t.transmit(rabbit); //эквивалент rabbit(10,10.0,'a');
//если не указать функцию получения, то кортеж будет считать что rabbit - это функтор
//передача через operator()

...

my::Any args[3]; // аналог boost::any, способен хранить объект любого типа

t.transmit(args); //кортеж распознает, что передача осуществляется в "массив", и знает, как это правильно сделать
//массив будет заполнен через цикл. Элемент массива обязан суметь принимать типы данных кортежа


Вся сложность шаблонов будет инкапсулирована внутри одного лишь my::tuple, который будет отвечать за хранения данных разных типов, и наполнение этим данными других объектов.









« Последнее редактирование: Июль 23, 2013, 09:14 от _Bers » Записан
ssoft
Гость
« Ответ #8 : Июль 23, 2013, 09:20 »


Почему бы тогда ни сделать просто: взять с++11 и не мучаться с велосипедами?


В некоторых проектах есть такие требования  В замешательстве, старые старые IDE => старые компиляторы.
Записан
ssoft
Гость
« Ответ #9 : Июль 23, 2013, 09:43 »


Как вариант вот такой дизайн самодельных кортежей:


Кортежи - это, конечно, хорошо, но громоздко в использовании.
Легче тогда уж так

Код
C++ (Qt)
 
double coords[3] = { 1.0, 2.0, 3.0 };
Point p = Point( coords );
 
 

чем

Код
C++ (Qt)
 
my::tuple< double, double, double > t( 1.0, 2.0, 3.0 );
Point p;
t.transmit( p, &Point::setValues );
 
 
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #10 : Июль 23, 2013, 11:42 »

Пока что я использую такой подход

// Для одного аргумента

// Для двух аргументов

и т.д. для любого количества, пока не надоест писать  Смеющийся

В бусте и Александреску так и делают в различной степени тяжести Улыбающийся. Если ничего, кроме инициализации массива не надо, то похоже это и будет оптимальным вариантом. Или не городить огород и таки писать в коде лишнюю строчку:
Код
C++ (Qt)
double coords[3] = { 1.0, 2.0, 3.0 };
Point p = Point( coords );

А вообще в С++11 можно вот так делать Улыбающийся:
Код
C++ (Qt)
typedef double Double3[3];
typedef Point< double, 3 > Point3d;
 
int main(int argc, char *argv[])
{
   ...
   Point3d p( Double3{ 1.0, 2.0, 3.0 } );
   ...
}
Записан

Пока сам не сделаешь...
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #11 : Июль 23, 2013, 13:17 »

старые старые IDE => старые компиляторы.

Если это Visual Studio, то, начиная с VS 2010, можно использовать компиляторы из других SDK. Visual Studio Platform Toolset.
Записан

Пока сам не сделаешь...
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.281 секунд. Запросов: 19.