2017-02-10 24 views
1

假設我有一個函數foo,即需要兩個不同類型的非原始對象,例如:將參數傳遞給一個C++沒有特定的順序功能

void foo(House h, Dog d) {// implementation } 

假定這些論點,即放置已沒有影響那麼理論上函數輸出foo(h,d)= foo(d,h)。但是C++不允許這樣,除非通過我重載此功能:

void foo (Dog d, House h) {// implementation } 

但這重載的對接成爲疼痛如果參數的數量增加(例如6超載3個參數等)。

我的問題是,是否有任何簡單的方法來達到傳遞參數的傳承方式,而不是按照特定的順序進行,而沒有重複的重載?

+4

出於好奇,爲什麼會有人想以錯誤的順序將參數傳遞給函數? – DyZ

+0

爲什麼你需要這種靈活性?如果你構造它,你可以按照定義的順序傳遞它們。 –

+0

如果你知道這個函數需要3種不同類型的參數,那麼能否以任何順序傳遞它們而不是檢查函數prototyoe是否方便? – Arash

回答

0

As far as I can tell,似乎沒有被複制在C Python而風格的關鍵字參數++(一個遠遠超出在提供軟件工程線程上市的方式。

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)只要它的互斥部分每次訪問。)

+0

該元組包含引用,並且您嘗試將''get''裸類型取出。在嘗試將它們與參數匹配以使此方法起作用之前,您必須編寫自己的'get'來衰減元組中的類型。 –

+0

@yurikilochek謝謝,修正。 (而不是重新實現/ shimming' get',我轉換爲按值傳遞。) – Potatoswatter

+0

我真的很喜歡你的答案。我能看到的唯一問題是,如果因爲'std :: get'的工作方式而有兩次相同的類型,那就是UB。我錯了嗎?這可能是一個強大的限制。 – skypjack

1

一般來說,我t最好減少傳遞給函數的參數數量。有兩種方法可以做你想做的事。

  • 創建一個具有這些非原始數據作爲成員變量的類。一旦這些成員被激勵,您可以調用一個成員函數來處理這些成員數據

  • 將這些非原始數據封裝在一個對象中,並通過引用您的函數傳遞此對象。

無論哪種方式,你不需要擔心命令的參數只要所有參數進行初始化。

+0

我同意封裝可能是一個解決方案,但爲每個獨立功能製作類或結構是不實際的。是嗎?也許我錯了,或者我問了一個不好的問題。 – Arash

+0

不,我不主張爲每個獨立功能創建類或結構。基本上,您需要確定哪些函數在哪些數據上運行,並且是否有範圍將這些數據以封裝格式結合在一起,以便您擁有相關的成員函數,以處理他們感興趣的數據。另外,還有一點需要注意一個班級或一個職能應該有單一的責任。 – Rishi

+0

按照何種順序將參數傳遞給您希望他創建的這個類的構造函數? – user12341234

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重鑄對象或實現對父類全局函數。

另一種方法可能是使用模板。

+0

這拋棄了編譯時安全的任何概念。你需要dynamic_casts來檢索類型。 –

1

它很可能重新n階論點爲O(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 

待辦事項不能將此視爲對此技術的認可。相反:即使有可能,請不要這樣做。

0

有什麼簡單的方法來達到傳遞參數的傳承方式,而不是按照特定的順序進行,沒有重複的重載?

是的,你可以做到這一點,但是因爲你沒有說過你對這個函數的確切用法,所以我不能給你通用的解決方案。無論如何,對於所有在評論中聲稱,問題作者需要的行爲是錯誤的,不好的,愚蠢的等等,請考慮下面的一段代碼,它的工作原理和我看到的潛力。

我們假設我們有一個存儲一些值的字段,我們希望有一個setter(也可能是getters)來訪問這些值(爲了清晰起見,我只給出了最小版本)。

所以,這個類將是:

struct A { 
    int g1 {}; 
    int g2 {}; 
    int g3 {}; 
}; 

這個類沒有制定者或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 

就像我說的,我不知道這是否符合您的需求,但這只是一個例子,如何做到這一點,這可能對您有所幫助。

儘管如此,將值設置爲未指定的順序(連同任意數量的值)的優點是,您只能設置所需的值。