w C++ 03, masz różne możliwości:
- generują przeciążeń 0-N argumentów (na przykład z wykorzystaniem Boost.Preprocessor)
- użytku minusy wykazach (
cons(1)("some string")(foo)
)
- użytku Przedmiot i pewne przeciążenia operatora (
operator()
na przykład, czy operator%
jak Boost.Format)
pierwszą opcją jest nieco skomplikowane, czuję dlatego nie każdy może łatwo zrozumieć makra, więc zarezerwowałbym go tylko dla rozwiązań krótkoterminowych, jeśli wkrótce planujesz migrację do C++ 0x.
Trzecia opcja może zapewnić miły niestandardowy dotyk (formatowanie odbywa się za pomocą znaku %
w wielu językach), ale oznacza to również, że należy pamiętać, że ta konkretna funkcja "variadic" działa za każdym razem.
Moje osobiste preferencje jest podejście cons
ponieważ rozwiązuje oba problemy:
- definicja obejmuje tylko szablony, więc jest bardziej czytelny i maintanable niż 1.
- zdefiniować minusy-Machinery raz, i można ponownie wykorzystać go w dowolnym funkcji „o zmiennej liczbie argumentów” (i pozostają funkcji), więc jest bardziej spójna i zapisuje pracy
na przykład, oto jak to może działać:
Układ składa, że ten przykład użyje:
#include <cassert>
#include <iostream>
#include <string>
pomocnik dla podać wynik dołączanie wartość (może to być bardziej efektywne z poprzedzenie, ale Oznaczałoby to, że przekazując argumenty w odwrotnej kolejności, co jest sprzeczne z intuicją):
template <typename T, typename Next> struct Cons;
struct ConsEmpty;
template <typename Cons, typename U>
struct cons_result;
template <typename U>
struct cons_result<ConsEmpty, U> {
typedef Cons<U, ConsEmpty> type;
};
template <typename T, typename U>
struct cons_result<Cons<T, ConsEmpty>, U> {
typedef Cons<T, Cons<U, ConsEmpty> > type;
};
template <typename T, typename Next, typename U>
struct cons_result<Cons<T, Next>, U> {
typedef Cons<T, typename cons_result<Next, U>::type> type;
};
Szablon sam Cons
, z magicznym operator()
dołączyć wartość. Zauważ, że tworzy nowy element z innego typu:
template <typename T, typename Next>
struct Cons {
Cons(T t, Next n): value(t), next(n) {}
T value;
Next next;
template <typename U>
typename cons_result<Cons, U>::type operator()(U u) {
typedef typename cons_result<Cons, U>::type Result;
return Result(value, next(u));
}
};
struct ConsEmpty {
template <typename U>
Cons<U, ConsEmpty> operator()(U u) {
return Cons<U, ConsEmpty>(u, ConsEmpty());
}
};
template <typename T>
Cons<T, ConsEmpty> cons(T t) {
return Cons<T, ConsEmpty>(t, ConsEmpty());
}
zrewidowana VarPrint
z nim:
bool VarPrint(std::ostream& out, const std::string& s, ConsEmpty) {
std::string::size_type offset = 0;
if((offset = s.find("%")) != std::string::npos) {
if(offset == s.size() - 1 || s[offset + 1] != '%') {
assert(0 && "Missing Arguments!");
return false;
}
}
out << s;
return true;
}
template<typename T, typename Next>
bool VarPrint(std::ostream& out,
std::string const& s,
Cons<T, Next> const& cons)
{
std::string::size_type prev_offset = 0, curr_offset = 0;
while((curr_offset = s.find("%", prev_offset)) != std::string::npos) {
out << s.substr(prev_offset, curr_offset);
if(curr_offset == s.size() - 1 || s[curr_offset + 1] != '%') {
out << cons.value;
if(curr_offset + 2 < s.length())
return VarPrint(out, s.substr(curr_offset + 2), cons.next);
return true;
}
prev_offset = curr_offset + 2;
if(prev_offset >= s.length())
break;
}
assert(0 && "Extra Argument Provided!");
return false;
}
a demo
int main() {
VarPrint(std::cout, "integer %i\n", cons(1));
VarPrint(std::cout, "mix of %i and %s\n", cons(2)("foo"));
}
można sprawdzić wyjście na ideone:
integer 1
mix of 2 and foo
Jest niemożliwe, jeśli chcesz dowolną ilość argumentów. Wszystko, co możesz zrobić, to dostarczyć implementacje dla określonej liczby argumentów, takich jak 1-10 argumentów. – Dani
Kompilowanie twojego przykładu: 'prev_offset> = s.length' -> zanotuj brakujące'() ', aby wywołać funkcję' length' :) –
Dziękuję. Brakowało mi '()', podczas pisania bezpośrednio. hah: D – winnerrrr