如何将可变数量的参数传递给构造函数?

时间:2017-05-01 03:21:22

标签: c++ string constructor arguments

我想为我的一个类编写一个构造函数,它在一组预定义的参数之后获取可变数量的std::string个参数。

我目前的代码如下:

// Audio.h
#include <string>
class Audio {
public:
    Audio(std::string title, std::string author);
protected:
    std::string title, author;
}

// Song.h
#include "Audio.h"
class Song : public Audio {
public:
    Song(std::string title, std::string artist) : Audio(title, artist);
    // I have working code to populate mFeatures from features
    Song(std::string title, std::string artist, std::string *features) 
        : Audio(title, artist);
private:
    std::string *mFeatures;
}

所以我有一个带string, string的构造函数和一个带string, string, *string的构造函数。我想写一个用string, string后跟任意数量的字符串来填充mFeatures

我环顾四周,找到this questionthis question,其中列出了成员函数的想法,但我没有找到与构造函数相关的答案。

TL; DR:有没有办法可以创建一个构造函数,它接受两个string参数后跟任意数量的string个参数?

5 个答案:

答案 0 :(得分:2)

执行此操作的最佳方法是使用初始化列表。

// Song.h

#include "Audio.h"
class Song : public Audio {
public:
    Song(std::string title, std::string artist, std::initializer_list<std::string> features) : Audio(title, artist), mFeatures(features) {};
private:
    std::vector<std::string> mFeatures;
};

用法:

Song s("title", "artist", {"f1", "f2"});

他们可以迭代。更多信息请访问:http://en.cppreference.com/w/cpp/utility/initializer_list。此外,您不应该按值传递titleartist(除非您想了解std::move),请通过const引用传递它们。

不要使用指向std::string的指针来保持动态字符串数组;你可能会以这种方式泄漏内存,还有其他各种问题。只需使用vector

实例:http://coliru.stacked-crooked.com/a/0e8914411dba674f

答案 1 :(得分:2)

尽管@NirFriedman的答案是正确的,但我不喜欢以下表格:

Song s("title", "artist", {"f1", "f2"});

我宁愿使用这样的表格:

Song s("title", "artist", "f1", "f2");

这几乎是相同的,但事实上你不必使用std::initializer_list

C ++ 17版本(参见wandbox):

#include<string>
#include<vector>
#include<type_traits>

class Audio {
public:
    Audio(std::string title, std::string author)
        : title{title}, author{author} {}
protected:
    std::string title, author;
};

class Song : public Audio {
public:
    template<typename... T>
    Song(std::string title, std::string artist, T... features)
        : Audio(title, artist), mFeatures{features...}
    {
        static_assert(std::conjunction_v<std::is_convertible<T, std::string>...>);
}

private:
    std::vector<std::string> mFeatures;
};

int main() {
    Song song{"foo", "bar", "..."};
}

C ++ 14替代方案(参见wandbox):

class Song : public Audio {
    template<bool... B>
    static constexpr bool check = std::is_same<
        std::integer_sequence<bool, true, B...>,
        std::integer_sequence<bool, B..., true>
    >::value;

public:
    template<typename... T>
    Song(std::string title, std::string artist, T... features)
        : Audio(title, artist), mFeatures{features...}
    {
        static_assert(check<std::is_convertible<T, std::string>::value...>, "!");
    }

private:
    std::vector<std::string> mFeatures;
};

static_assert的优点是,它可以帮助在出现错误时打印更加用户友好的错误消息。请注意,在上面的示例中,分配mFeatures{features...}也会给您一个错误。无论如何,您可以决定在构造函数体内详细说明features...并在检测到不一致时立即停止编译

答案 2 :(得分:0)

模板也可以在构造函数上工作,并且通过扩展也可以使用可变参数模板。如果你已经尝试过它并且它不起作用,请检查你是如何编译它的。

答案 3 :(得分:0)

您应该传递字符串,字符串,然后传递字符串向量。在向量中存储任意数量的字符串。这可能是解决这个问题的最好方法。

答案 4 :(得分:0)

template <typename ...List>
Song(const std::string& title, const std::string& artist, List&&... features) : Audio(title, artist)

然后只使用特征形式作为私有成员函数的参数,该函数设置特征成员就像您链接的示例一样。您链接的那个主题中的最佳答案也适用于您。