我来自Swift背景,虽然我也知道一些C,但这是我第一次编写C ++代码。
在Swift中,可以编写一个带有任意数量参数的函数:
func foo(bar: String...) {
// ...
}
和bar
可以是任何类型(String,Bool,Struct,Enum等)。
我想知道在C ++中是否可以做同样的事情。所以,理想情况下我会写:
struct X {
string s;
X(int);
// ...
}
void foo(string s, ...) {
// ...
}
foo("mystr", X(1), X(2), X(3));
和foo
内部我会以某种方式访问参数列表,有点类似于printf
函数。
现在我使用vector<X>
作为参数,因为所有参数都有X类型。但是,在我看来,这使得调用foo
有点难看:
foo("mystr", { X(1), X(2), X(3) });
由于我对C ++缺乏了解,我没有看到任何解决方案?
修改
这是我想要在foo
内完成的任务:
string ssub(string s, vector<X> v) {
int index, i = 0;
while (1) {
index = (int)s.find(SUB);
if (index == string::npos) { break; }
s.erase(index, string(SUB).size());
s.insert(index, v[i].tostr());
i++;
}
return s;
}
基本上,只要我给出了顺序访问参数的方法,一切都很好。
答案 0 :(得分:1)
这是众多方法中的一种。
您可以将整个程序复制/粘贴到IDE /编辑器中。
#include <utility>
#include <iostream>
#include <typeinfo>
#include <string>
//
// define a template function which applies the unary function object func
// to each element in the parameter pack elems.
// @pre func(std::forward<Elements>(elems)) must be well formed for each elems
// @returns void
//
template<class Function, class...Elements>
auto do_for_all(Function&& func, Elements&&...elems)
{
using expand = int[];
void(expand { 0, (func(elems), 0)... });
}
// a test structure which auto-initialises all members
struct X
{
int i = 0;
std::string s = "hello";
double d = 4.4;
};
//
// The function foo
// introduces itself by writing intro to the console
// then performs the function object action on each of args
// @note all arguments are perfectly forwarded - no arguments are copied
//
template<class...Args>
auto foo(const std::string& intro, Args&&...args)
{
std::cout << "introducing : " << intro << std::endl;
auto action = [](auto&& arg)
{
std::cout << "performing action on: " << arg
<< " which is of type " << typeid(arg).name() << std::endl;
};
do_for_all(action, std::forward<Args>(args)...);
}
int main()
{
// make an X
auto x = X(); // make an X
// foo it with the intro "my X"
foo("my X", x.i, x.s, x.d);
}
示例输出:
introducing : my X
performing action on: 0 which is of type i
performing action on: hello which is of type NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
performing action on: 4.4 which is of type d
答案 1 :(得分:0)
您可以使用variadic templates(自C ++ 11起):
template <typename ... Type>
void foo(Type& ... args) {
// do whatever you want, but this may be tricky
}
foo(X(1), X(2), X(3));
min
函数这是我编写的代码,用于在计算最少值时忽略对std::min
的丑陋调用。
#include <type_traits>
namespace my {
template <typename A, typename B>
auto min(const A& a, const B& b) -> typename std::common_type<A, B>::type {
return (a<b)?a:b;
}
template <typename A, typename B, typename ... T >
auto min(const A& a, const B& b, const T& ... c) -> typename std::common_type<A, B, T ...>::type {
const typename std::common_type<A, B, T ...>::type tmp = my::min(b, c ...);
return (a<tmp)?a:tmp;
}
}
// calculating minimum with my::min
my::min(3, 2, 3, 5, 23, 98);
// doing the same with std::min
std::min(3, std::min(2, std::min(3, std::min(5, std::min(23, 98))))); // ugh, this is ugly!
这是一个棘手的部分:您不能像使用vector
那样循环访问参数包。您将不得不进行一些递归,如示例所示。
答案 2 :(得分:0)
您可以编写一个可变参数模板函数,将参数传递给某些std::initializer_list
并迭代列表,例如:
#include <initializer_list>
template <typename ... Args>
void foo(Args && ... args) {
std::initializer_list<X> as{std::forward<Args>(args)...};
for (auto const & x : as)
// Use x here
}
int main() {
foo(1, 2, 3, 4, 5);
}
另请注意,您可能希望更改参数列表和初始化列表的类型以满足您的确切用例。例如。使用Args * ... args
和std::initializer_list<X *>
或类似内容。