2017-01-15 26 views
0

我在設計一個供內部使用的庫。從模板參數中獲取字段值而不是直接訪問以允許使用不同名稱獲取相同信息的函數

函數可以

template<typename It> 
void doStuff(It begin, It end) 
{ 
    // This is example code. The point is to show that I access the data of the iterator 
    doStuffInternal(it->a, it->b, it->c); 
} 

這個函數是一個模板,因爲我要接受所有類型的迭代器,但我對特定類型的期望,這個迭代器產生。

目前我的代碼假定的對象與結構方式通

struct A 
{ 
     int a; 
     std::string b; 
     BigObject c; 
}; 

我知道這個功能會從外部API接收數據的調用代碼,數據看起來像

struct AlmostA 
{ 
    int a_; 
    std::string _b; 
    AlmostBigObject cc; 
}; 

現在我不能把這AlmostA傳遞給我的功能,我需要將其轉換爲A(或東西,行爲像A),即使所有的信息都在AlmostA,只是不同的名稱(和稍微不同的類型)。

什麼,我想這樣做是爲了創建一個函數來訪問領域

inline int getA(const &A a) 
{ 
    return a.a; 
} 

inline std::string& getB(const &A a) 
{ 
    return a.b; 
} 

等每一個領域,我需要訪問,然後重寫我的功能是

template<typename It> 
void doStuff(It begin, It end) 
{ 
    doStuffInternal(getA(*it), getB(*it), getC(*it)); 
} 

然後調用代碼可以定義

inline int getA(const &AlmostA a) 
{ 
    return a.a_; 
} 

inline std::string& getB(const &AlmostA a) 
{ 
    return a._b; 
} 

,並調用我的函數的迭代器沒有任何轉換。

我希望這樣做的是,調用代碼可以定義它們如何提供信息,而不必被強制具有這些特定字段的結構。

我搜索了一下,找不到任何代碼做這個例子。我對C++相對來說比較陌生,所以我想如果這樣做會起作用,這種方法的缺陷是什麼,它爲什麼不流行或者不被使用(我知道某種類似的東西是用std做的: :交換,但這是一個特定的功能)在C++世界中以統一的方式呈現具有不同接口的數據的替代解決方案是什麼?

爲了讓編譯器找到它們,getter函數需要實現哪些名稱空間?

+0

如果你想要做的是每個循環,您可以使用[的std :: for_each的(http://en.cppreference.com/w/cpp/algorithm/for_each)(也許與拉姆達) –

+0

這個函數裏面的內容是無關緊要的,這只是一個例子。我打算對這些數據進行操作,問題是如何以通用方式提供對這些數據的訪問 –

+0

爲什麼你不能將'AlmostA'傳遞給你的函數? – Unimportant

回答

1

doStuffInternal(getA(*it), getB(*it), getC(*it))似乎固體我 - 我會用一個struct模板明確的專業化爲每個需要支持的類型。

template <typename T> 
struct adapter; 

template <> 
struct adapter<A> 
{ 
    template <typename T> 
    decltype(auto) a(T&& x) { return forward_like<T>(x.a); } 

    template <typename T> 
    decltype(auto) b(T&& x) { return forward_like<T>(x.b); } 

    // ... 
}; 

template <> 
struct adapter<AlmostA> 
{ 
    template <typename T> 
    decltype(auto) a(T&& x) { return forward_like<T>(x.a_); } 

    template <typename T> 
    decltype(auto) b(T&& x) { return forward_like<T>(x._b); } 

    // ... 
}; 

使用decltype(auto)返回類型和forward_like允許您保留x的成員的值類別:

static_assert(std::is_same<decltype(adapter<A>::a(A{})), int&&>{}); 

A lvalue{}; 
static_assert(std::is_same<decltype(adapter<A>::a(lvalue)), int&>{}); 

const A const_lvalue{}; 
static_assert(std::is_same<decltype(adapter<A>::a(const_lvalue)), const int&>{}); 

wandbox example(of the value category propagation)


最終代碼會看起來像這個:

template<typename It> 
void doStuff(It begin, It end) 
{ 
    adapter<std::decay_t<decltype(*it)>> adp; 
    doStuffInternal(adp.a(*it), adp.b(*it), adp.c(*it)); 
} 

在C++ 11,你需要明確指定使用後返回類型返回類型。例如:

template <typename T> 
auto a(T&& x) -> decltype(forward_like<T>(x.a_)) 
{ 
    return forward_like<T>(x.a_); 
} 
+0

這是否適用於C++ 11? –

+0

把代碼放到一個專門的結構中有什麼好處? –

+0

@Makers_F:不需要,您需要顯式指定具有*尾部返回類型*的返回類型。我將編輯我的問題 –

相關問題