Я пытаюсь написать (C ++ 98) программу, в которой встречается следующий шаблон: у меня есть очень простой универсальный класс кортежей, и мне нужно заполнить его значениями, созданными с использованием фабрики. Минимальный пример кода ниже:
#include <iostream>
class diagnostics
{
private:
int payload;
public:
diagnostics(int a)
: payload(a)
{
std::cout << "constructor\n";
}
diagnostics(const diagnostics& o)
: payload(o.payload)
{
std::cout << "copy constructor\n";
}
~diagnostics()
{
std::cout << "destructor [" << payload << "]\n";
}
};
struct creator
{
static diagnostics create()
{
static int i = 0;
return diagnostics(++i);
}
};
template<class Head, class Tail>
struct tuple
{
Head head;
Tail tail;
typedef Head head_t;
typedef Tail tail_t;
tuple(const Head& h, const Tail& t)
: head(h), tail(t)
{
}
};
struct empty_tuple { };
template<class Tuple, class Create>
struct create_helper
{
static Tuple create()
{
return Tuple(Create::create(),
create_helper<typename Tuple::tail_t, Create>::create());
}
};
template<class Create>
struct create_helper<empty_tuple, Create>
{
static empty_tuple create()
{
return empty_tuple();
}
};
template<class Tuple, class Create>
Tuple create()
{
//return Tuple(Create::create(), empty_tuple()); //(*)
return create_helper<Tuple, Create>::create();
}
int main()
{
typedef tuple<diagnostics, empty_tuple> tuple_t;
tuple_t a = create<tuple_t, creator>();
}
Выход
constructor
copy constructor
destructor [1]
destructor [1]
Я хотел бы избавиться от двух средних линий.
Для упрощения обсуждения мы можем в приведенном выше коде раскомментировать строку, помеченную (*); это нарушит щедрость, но не программу.
Теперь к моему основному вопросу: Как я могу исправить эту ситуацию? Что-то в стандарте предотвращает RVO (по-видимому, RVO здесь придется делать рекурсивно)? Если нет, принимая, что компилятор просто недостаточно хорош, есть ли способ, которым я могу заставить это произойти явным образом? Я в порядке с усложнением callside create (), но я не хочу усложнять объекты в кортеже (в частности, некоторые из них не могут быть построены по умолчанию, и я не хочу вводить дополнительные «унитаризованные») говорится им). Может ли заменить новое, может быть, помочь?
Следующий вопрос кажется связанным, но в конечном итоге не помог: Почему здесь не происходит RVO?)
Я чувствую себя немного глупо, чтобы ответить на свой вопрос через пять минут, но, похоже, это самый подходящий способ донести следующую информацию:
Вот одно из решений. Мы можем перенести код создания в сам класс tuple:
struct FILLIT { };
template<class Head, class Tail>
struct tuple
{
Head head;
Tail tail;
typedef Head head_t;
typedef Tail tail_t;
tuple(const Head& h, const Tail& t)
: head(h), tail(t)
{
}
tuple(const tuple& o)
: head(o.head), tail(o.tail)
{
std::cout << "tuple copy\n";
}
template<class Create>
tuple(FILLIT, Create c)
: head(Create::create()), tail(FILLIT(), c)
{
}
};
struct empty_tuple
{
empty_tuple() {};
template<class C>
empty_tuple(FILLIT, C) {};
};
Совместимая реализация create
template<class Tuple, class Create>
Tuple create()
{
return Tuple(FILLIT(), Create());
}
Я все еще был бы заинтересован в других методах.
Других решений пока нет …