C++ C++;不带第一个变量的可变参数

C++ C++;不带第一个变量的可变参数,c++,function,c++11,variadic,C++,Function,C++11,Variadic,有没有可能使用可变参数,而不指定第一个参数 例如: 这个代码非常好: void something(const char* layoutAndButton, ...) { va_list ap; va_start(ap, layoutAndButton); std::map<std::string, std::string> data; while (*layoutAndButton != '\0') { std::string lay

有没有可能使用可变参数,而不指定第一个参数

例如:

这个代码非常好:

void something(const char* layoutAndButton, ...)
{
    va_list ap;
    va_start(ap, layoutAndButton);
    std::map<std::string, std::string> data;
    while (*layoutAndButton != '\0') {
        std::string layout = va_arg(ap, const char*);
        ++layoutAndButton;
        std::string button = va_arg(ap, const char*);
        ++layoutAndButton;
        data.insert(std::make_pair(layout, button));
    }
    for (auto const& x : data)
    {
        std::cout << x.first << ':' << x.second << std::endl;
    }
    va_end(ap);
}
有可能做那样的事吗?然后才能访问成员?如果是,如何进行


谢谢

这里是如何使用C++变量模板。您可以使用任意偶数的
const char*
参数调用
something()
,例如
something(“k1”、“v1”、“k2”、“v2”)
。它将通过递归调用
buildMap()
函数,从这些参数构建一个
map
,然后调用
useMap()
来执行您希望对映射执行的任何实际操作

void buildMap(std::map<std::string, std::string>& data) 
{
}

template<typename... Args>
void buildMap(
    std::map<std::string, std::string>& data, 
    const char* layout, 
    const char* button, 
    Args... args) 
{
    data.insert(std::make_pair(layout, button));
    buildMap(data, args...);
}


void useMap(std::map<std::string, std::string>& data) 
{
    // TODO: do something here
}

template<typename... Args>
void something(Args... args) {
    std::map<std::string, std::string> data;
    buildMap(data, args...);
    useMap(data);
}
void buildMap(标准::映射和数据)
{
}
模板
虚空构建图(
标准::地图和数据,
常量字符*布局,
常量字符*按钮,
Args…Args)
{
插入数据(标准::生成对(布局、按钮));
构建地图(数据、参数…);
}
void useMap(标准::映射和数据)
{
//托多:在这里做点什么
}
模板
使某物无效(Args…Args){
地图数据;
构建地图(数据、参数…);
使用地图(数据);
}

注释中的状态
std::initializer\u list
似乎完成了这项工作

void something(std::initializer_list<std::pair<std::string, std::string>> layoutAndButtons)
{
    // std::map<std::string, std::string> m(layoutAndButtons); // potentially
    for (auto const& p : layoutAndButtons) {
        std::cout << p.first << ':' << p.second << std::endl;
    }
}
如果您确实需要可变模板,我建议:

template<typename... Args>
void something(Args... args) 
{
    static_assert(sizeof...(Args) % 2 == 0, "wrong number of argument");
    const char* layoutAndButtons[] = {args...};

    std::map<std::string, std::string> m;
    for (auto it = std::begin(layoutAndButtons);
         it != std::end(layoutAndButtons);
         it += 2) {
        auto layout = *it;
        auto button = *(it + 1);
        m.emplace(layout, button);
    }
    for (auto const& p : m)
    {
        std::cout << p.first << ':' << p.second << std::endl;
    }
}
模板
使某物无效(Args…Args)
{
静态断言(sizeof…(Args)%2==0,“参数数目错误”);
const char*layoutAndButtons[]={args…};
std::map m;
对于(自动it=std::begin)(布局按钮);
it!=std::end(布局按钮);
it+=2){
自动布局=*it;
自动按钮=*(it+1);
m、 安放(布局、按钮);
}
用于(自动常数和p:m)
{
std::cout如果可以使用C++14(
std::index_sequence
std::make_index_sequence
),可以避免递归将
args…
包装在
std::tuple
中,生成索引列表,并使用索引和
std::get()
初始化
std::map

我的意思是:如果你写一个助手函数如下

template <typename ... Args, std::size_t ... Is>
std::map<std::string, std::string> getMap
   (std::tuple<Args...> const & t, std::index_sequence<Is...> const &)
 { return { {std::get<(Is<<1)>(t), std::get<(Is<<1)+1U>(t)} ... }; }
auto data = getMap(std::tie(args...),
                   std::make_index_sequence<(sizeof...(Args)>>1)>{});
但是我也建议在这一行前面加一个
static\u assert()
,检查
args的数量是否为偶数…
,类似于

static_assert( (sizeof...(Args) & 1U) == 0U, "#Args is odd!"); 
下面是一个完整的工作示例

#include <map>
#include <tuple>
#include <iostream>
#include <type_traits>

template <typename ... Args, std::size_t ... Is>
std::map<std::string, std::string> getMap
   (std::tuple<Args...> const & t, std::index_sequence<Is...> const &)
 { return { {std::get<(Is<<1)>(t), std::get<(Is<<1)+1U>(t)} ... }; }

template <typename... Args>
void something (Args... args)
 {
   static_assert( (sizeof...(Args) & 1U) == 0U, "#Args is odd!");

   auto data = getMap(std::tie(args...),
                      std::make_index_sequence<(sizeof...(Args)>>1)>{});

   for ( auto const & p : data )
      std::cout << '[' << p.first << ',' << p.second << ']';

   std::cout << std::endl;
 }

int main ()
 {
   something("k1", "v1", "k2", "v2", "k3", "v3"); // compile
   //something("k1", "v1", "k2", "v2", "odd!"); // static_assert() failure
 }
#包括
#包括
#包括
#包括
模板
std::map getMap
(std::tuple const&t,std::index_sequence const&)

{return{std::getHow关于可变模板而不是旧的C-省略号?可以编写
void something(…)
这将是or或等的副本。同意@Jarod42。C++11的可变模板允许我们编写var args函数的类型安全版本。顺便说一句,在您的情况下,
void something(std::initializer_list)
似乎更合适。尽管我投了赞成票——这肯定很有趣——但老实说,我发现它比我的递归
getMap()
@arthurtaca更令人困惑——因为你低估了索引生成的黑暗面的力量……嗯……我的意思是……是的,可能更难理解。
auto data = getMap(std::tie(args...),
                   std::make_index_sequence<(sizeof...(Args)>>1)>{});
static_assert( (sizeof...(Args) & 1U) == 0U, "#Args is odd!"); 
#include <map>
#include <tuple>
#include <iostream>
#include <type_traits>

template <typename ... Args, std::size_t ... Is>
std::map<std::string, std::string> getMap
   (std::tuple<Args...> const & t, std::index_sequence<Is...> const &)
 { return { {std::get<(Is<<1)>(t), std::get<(Is<<1)+1U>(t)} ... }; }

template <typename... Args>
void something (Args... args)
 {
   static_assert( (sizeof...(Args) & 1U) == 0U, "#Args is odd!");

   auto data = getMap(std::tie(args...),
                      std::make_index_sequence<(sizeof...(Args)>>1)>{});

   for ( auto const & p : data )
      std::cout << '[' << p.first << ',' << p.second << ']';

   std::cout << std::endl;
 }

int main ()
 {
   something("k1", "v1", "k2", "v2", "k3", "v3"); // compile
   //something("k1", "v1", "k2", "v2", "odd!"); // static_assert() failure
 }