假设我有一个函数foo,它接受两个不同类型的非原始对象,例如:
$ionic platform remove android
$ionic hooks add
$ionic platform android
$ionic build android
假设这些参数的放置对函数输出没有影响,那么理论上foo(h,d)= foo(d,h)。但除非我通过以下方式重载此函数,否则c ++不允许这样做:
void foo(House h, Dog d) {// implementation }
但是如果参数的数量增加(例如,3个参数的6次重载等等),这种重载就会成为痛苦的对象。
我的问题是,在没有重复超载的情况下,有没有简单的方法来实现不按特定顺序传递参数的方便?
答案 0 :(得分:1)
在C ++ 17中,我们有std::get<T>(std::tuple)
。这可以与std::forward_as_tuple
:
template< typename ... unordered_arg >
void foo( std::tuple< unordered_arg ... > arg_set ) {
House h = std::get< House && >( std::move( arg_set ) );
Dog d = std::get< Dog && >( std::move( arg_set ) );
// implementation
}
template< typename ... arg >
void foo( arg ... a )
{ foo_impl( std::forward_as_tuple( std::move( a ) ... ) ); }
(只要每次访问互相排斥的部分,就可以乘以move(arg_set)
。)
答案 1 :(得分:1)
一般来说,最好减少传递给函数的参数数量。有两种方法可以做你想做的事。
创建一个具有这些非原始数据作为成员变量的类。一旦这些成员被初始化,您就可以调用对这些成员数据进行操作的成员函数
将这些非原始数据封装在一个对象中,并通过引用将该对象传递给您的函数。
无论哪种方式,只要所有参数都被初始化,您就不必担心参数的顺序。
答案 2 :(得分:1)
很有可能用O(n)包装器重新排序n个参数:
#include <iostream>
using namespace std;
struct A { int a; A(int a) : a(a) {} };
struct B { int b; B(int b) : b(b) {} };
struct C { int c; C(int c) : c(c) {} };
struct D { int d; D(int d) : d(d) {} };
static void foo(A a, B b, C c, D d) { cout << a.a << " " << b.b << " " << c.c << " " << d.d << endl; }
template<class ...Args> struct Foo { void operator()(Args...); };
template<class ...Args> static void foo(Args ...args) { Foo<Args...>()(args...); }
template<class T, class U> struct Foo<T, U, C, D> { void operator()(T t, U u, C c, D d) { foo(u, t, c, d); } };
template<class T, class U, class V> struct Foo<T, U, V, D> { void operator()(T t, U u, V v, D d) { foo(v, t, u, d); } };
template<class T, class U, class V, class W> struct Foo<T, U, V, W> { void operator()(T t, U u, V v, W w) { foo(w, t, u, v); } };
int main() {
foo(A(1), B(2), C(3), D(4));
foo(D(5), C(6), B(7), A(8));
return 0;
}
(包装类Foo
是必需的,因为函数不能部分专门化。)
$ c++ -std=c++11 a.cc
$ ./a.out
1 2 3 4
8 7 6 5
不要将此解释为对此技术的认可。相反:即使可能,请不要这样做。
答案 3 :(得分:0)
As far as I can tell,似乎没有办法在C ++中复制Python风格的关键字参数(超出了提供的软件工程线程中列出的方式。
答案 4 :(得分:0)
您可以使用层次结构来执行此操作,例如
class Object
{
public:
enum Type { Dog, House};
Type m_type;
};
class Dog : public Object
{
};
class House : public Object
{
};
void myFunction(const Object& a, const Object& b)
{
}
如果需要,您可以使用myFunction中的m_type重新构造对象,或者在父类上实现全局函数。
另一种方法可能是使用模板。
答案 5 :(得分:0)
有没有简单的方法来实现不按特定顺序传递参数的方便而没有重复超载?
是的,你可以这样做,但因为你还没有说明你对这个功能的确切用法,我无法为你提供通用的解决方案。无论如何,对于所有在评论中声称该问题的作者所需的行为是错误的,坏的,愚蠢的等等的人,请考虑下面的一段代码,这些代码可行,并且我看到了这方面的潜力。
我们假设我们有一个类,其中包含存储某些值的字段,我们希望有一个setter(也可能是getter)来访问这些值(为了清晰起见,我只提供了最小版本)。
所以,这个课程将是:
struct A {
int g1 {};
int g2 {};
int g3 {};
};
这个类没有setter或getter,因为我们要将它包装在不同的类Data
类中。
struct Data {
template <typename... Ts>
void set (Ts&&... ts) {
set_impl (std::forward<Ts> (ts)...);
}
A a;
private:
template <typename T>
void set_impl (T&& t) {
a.*T::mem = t.v; // (X)
}
template <typename T, typename K, typename... Ts>
void set_impl (T&& t, K&& k, Ts&&... ts) {
set_impl (std::forward<T> (t));
set_impl (std::forward<K> (k), std::forward<Ts> (ts)...);
}
};
所以这里我们有一个具有set
成员函数的类,它接受任意数字或参数,并且它们中的每一个都可以(并且在这个例子中应该是)不同类型。要像A
中那样设置(X)
字段,您需要传递一个指向A
成员的类型的对象。所以请看看下面的课程。
struct G {
G (int c = {}) : v {c} {}
int v;
};
struct G1 : G { using G::G; static constexpr int A::* mem = &A::g1; };
struct G2 : G { using G::G; static constexpr int A::* mem = &A::g2; };
struct G3 : G { using G::G; static constexpr int A::* mem = &A::g3; };
所有Gx
函数仅用于设置A
字段的值,并且每个字段都知道要设置的字段。
显示结果的辅助函数是:
void show (const A& v) {
std::cout << "g1 = " << v.g1 << std::endl;
std::cout << "g2 = " << v.g2 << std::endl;
std::cout << "g3 = " << v.g3 << std::endl;
}
最后,用法:
Data d;
d.set (G1 {10}, G2 {20}, G3 {30});
show (d.a);
Data p;
p.set (G3 {40}, G1 {-30}, G2 {120});
show (p.a);
给出了输出:
g1 = 10
g2 = 20
g3 = 30
g1 = -30
g2 = 120
g3 = 40
就像我说的,我不知道这是否符合您的需求,但这只是一个例子,如何做到这一点,它可能对您有所帮助。
尽管如此,将值设置为未指定的顺序(与任意数量的值一起使用)的优点是您只能设置所需的值。