Parametre paketinin gruplanmış veya eşlenmiş katlaması nasıl yapılır?


14
template<class Msg, class... Args>
std::wstring descf(Msg, Args&&... args) {
    std::wostringstream woss;

    owss << Msg << ". " << ... << " " << args << ": '" << args << "' ";//not legal at all

    //or

    owss << Msg << ". " << args[0] << ": '" << args[1] << "'  " << args[2] << ": '" << args[3] << "' "; //... pseudo code, and so on...
}

Bunun yerine çiftlerin bir listesini veya bunun gibi bir şey kullanabileceğimi biliyorum, ancak işlevin sözdizimini tutarken bunu nasıl yapacağımla ilgileniyorum:

const auto formatted = descf(L"message", "arg1", arg1, "arg2", arg2);

Yanıtlar:


9

Bir katlama ifadesi kullanabilirsiniz! En güzel değil *, ancak sunulan tüm katsız çözümlerden daha kısa:

template<class T, class ... Args>
std::wstring descf(T msg, Args&&... args) {
    std::wostringstream owss;
    owss << msg << ". ";

    std::array<const char*, 2> tokens{": '", "' "};
    int alternate = 0;
    ((owss << args << tokens[alternate], alternate = 1 - alternate), ...);

    return owss.str();
}

Örnek çıktı ile demo: https://godbolt.org/z/Gs8d2x

Her işlenenin bir çıktı argsve alternatif belirtecin yanı sıra belirteç dizinini değiştiren virgül operatörü üzerinde bir katlama gerçekleştiririz (son ikisi, başka bir virgül operatörü ile birleştirilir).

* Katlama ifadelerine (ve virgül operatörüne) aşina bir okuyucu için bu muhtemelen "en iyi" koddur, ancak herkes için tamamen anlamsızdır, bu yüzden kod tabanınıza bunu uygulamak isteyip istemediğinizi kendi kararınızı kullanın.


Sanırım bu da bir bool (sadece eşleştirme gerekiyorsa) ala ile çalışabilir. : b ^ = doğru; ve sonra belki de kiracı operatörü (b? ": '", ":"' ")
12'de darune

1
@darune Elbette, alternatifi ifade etmenin başka yolları da var. Çıkış / alternatif mantığı dizinin güzel bir şekilde gerçekleştirdiği gerçek belirteç değerlerinden ayırmaya karar verdim. Ben gelen örtük dönüştürme sevmediğim booliçin intben gerçek gitti bu yüzden dizine eklerken intdurumunu değiştirmek için. Postfix'e karşı postfix ++(en azından benim için) doğrulamak için ekstra zihinsel döngüler alırken, ayrı ayrı 1 - gerçekten yanlış okunamaz. Kısacası, bunu olabildiğince okunabilir tutmaya çalıştım, ancak bu elbette kişisel zevkinize (veya uygulanabilir stil kılavuzuna) bağlı. max66 çok daha fazla yoğunlaştırdı.
Max Langhof

std::arrayYerel bir dizi yerine kullanmak anlamsız bir komplikasyon gibi görünüyor.
Tekilleştirici

@Deduplicator Kesinlikle std::array<const char*, 2>daha fazla okunabilir bulduğum için kesinlikle katılmıyorum const char**. Ama yine, bu benim bazı oldukça belirsiz sözdizimi etrafında okunabilirliği en iyi atış, size kendi kodunuzu ne gibi onunla yapabilirsiniz. Tek yapabileceğim, okunabilir olduğunu düşündüğüm şeyin veri noktasını vermek.
Max Langhof

9

Bu, aşağıdaki modeli takip eden birkaç yardımcı işlevle kolaydır.

void helper() {}

template <class T1, class T2, class ... T>
void helper(T1 t1, T2 t2, T ... t)
{
     do_single_pair(t1, t2);
     helper(t...);
}

Bu bir katlama ifadesi değil, net sonuç aynı.


şablon özyineleme derinliği katlama ifadesinden farklı olacak mı? ya da aynı mı olacak
Darune

1
@ darune Katlama ifadeleri ile doğal bir özyineleme yoktur ... Katlama ifadeleri sadece bir ifadeye resmen genişler (varyasyon şablonunun bu özel örneğinde).
Max Langhof

6

Sanırım bir dizin ve üçlü bir operatörle deneyebilirsiniz.

Aşağıdaki gibi bir şey

template <typename ... Args>
std::wstring descf (std::wstring const & Msg, Args && ... args)
 {
   std::wostringstream woss;

   int i = 0;

   ((woss << Msg << ". "), ... ,(woss << args << (++i & 1 ? ": '" : "' ")));

   return woss.str();
 }

@MaxLanghof Bu, daha fazla ayırıcıya kolay genişletme avantajına (?) Sahiptir.
Tekilleştirici

@Deduplicator Ne demek istediğinizi anlamıyorum? Açıklayabilir misin?
Max Langhof

@Deduplicator - "Daha fazla ayırıcıya genişletme" ile ne demek istediğinizi net değil ... neyse ... bu çözüm kabul edilene çok benziyor; Az ya da çok genişletilebilir olduğunu düşünmüyorum. Ben biraz (küçük! Belki derleyici aynı şekilde optimize) daha hafif olduğunu varsayalım çünkü std::array(her neyse, hafif bir sınıftır) kullanmaktan kaçının ama (bu yüzden kabul edilen cevap tercih edilir) daha az okunabilir.
max66

2

Aşağıdaki kod hile yapmalıdır. Parametre paketi bir başlatıcı listesinde genişletilir.

#include <string>
#include <iostream>
#include <sstream>
#include <vector>

template <typename...Args>
std::string descf(std::string msg, Args &&... args)
{
   auto argumentsVector = std::vector<std::string>{args...};

   std::stringstream ss;
   ss << msg << ". ";

   for (auto i = std::size_t{0}; i < argumentsVector.size() - 1; ++i)
      ss << argumentsVector[i] << ": '" << argumentsVector[i+1] << "' ";

   auto result = ss.str();
   if (!argumentsVector.empty())
       result.pop_back();
   return result;
}

int main()
{
   std::cout << descf("message", "arg1", "1", "arg2", "2") << std::endl;
}

Bu, herkesin s'ye argsdönüştürülebilir olmasını gerektirir std::string.
ceviz

@ ceviz, bu doğru. Bu bir gereklilik
Mattias De Charleroy

1

İle std::index_sequence:

template <class Msg, class... Pairs>
std::wstring descf_pair(const Msg& msg, const Pairs&... pairs)
{
    std::wstringstream woss;

    woss << msg << ". ";
    auto sep = L"";
    ((woss << sep << std::get<0>(pairs) << L": '"
                  << std::get<1>(pairs) << L"'", sep = L"  "), ...);
    return woss.str();
}

template <class Msg, std::size_t... Is, class Tuple>
decltype(auto) descf_impl(const Msg& msg, std::index_sequence<Is...>, Tuple&& t)
{
    return descf_pair(msg, std::tie(std::get<2 * Is>(t), std::get<2 * Is + 1>(t))...);
}

template <class Msg, typename ... Ts>
std::wstring descf(const Msg& msg, const Ts&... ts)
{
    static_assert(sizeof...(Ts) % 2 == 0);

    return descf_impl(msg,
                      std::make_index_sequence<sizeof...(Ts) / 2>(),
                      std::tie(ts...));
}

gösteri

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.