2015-09-28 91 views
1

在下面的代碼:三元運營商的std :: index_sequence

#include <iostream> 
#include <utility> 
#include <set> 

template <typename... Args> 
void f(Args... args) { 
    std::cout << sizeof...(Args) << " elements.\n"; 
} 

template <std::size_t... Is> 
void g (std::index_sequence<Is...>, const std::set<int>& set) { 
    f((set.find(Is) == set.end() ? Is : 2*Is)...); 
} 

int main() { 
    g (std::make_index_sequence<10>{}, {1,3,7,8}); 
} 

我想f((set.find(Is) == set.end() ? Is : 2*Is)...);使用Is如果set.find(Is) == set.end()但沒有以其他方式(而不是2*Is)。因此傳遞的參數數量不固定。如何實現這一目標?

編輯: 對不起,但我簡化了這個問題太多。下面的代碼反映更真實的問題:

#include <iostream> 
#include <utility> 
#include <tuple> 

template <typename... Args> 
void f(Args... args) { 
    std::cout << sizeof...(Args) << " elements.\n"; 
} 

struct NullObject {}; 

template <typename Tuple, std::size_t... Is> 
void g (std::index_sequence<Is...>, const Tuple& tuple) { 
    f ((std::get<Is>(tuple) != std::get<Is+1>(tuple) ? std::get<Is>(tuple) : NullObject{})...); 
} 

int main() { 
    g (std::make_index_sequence<8>{}, std::make_tuple(2,1.5,'a','a',true,5,5,false)); 
} 

以上沒有因爲混合類型由三元運算符傳遞的編譯,但我認爲你可以在這裏看到我的想法。如果條件爲std::get<Is>(tuple) != std::get<Is+1>(tuple),我想通過NOTHING,所以我通過NullObject{},然後以某種方式嘗試從f的參數中刪除所有NullObjects,以獲得傳遞給f的真實參數。

+2

您不能與* ternary *表達式關聯。爲什麼不使用'if'語句?或者在三元表達式中調用'f'函數,而不是在'f'調用中使用三元表達式。 –

+0

如果你可以通過編譯類型替換你的'std :: set'內容,你可以這樣做:[Demo](https://ideone.com/ZBF92c) – Jarod42

+0

@ Jarod42對不起,我簡化了這個問題,更新了問題。我不確定你的技術是否仍然適用。 – prestokeys

回答

4

你不能使用三元運算符 - 這需要兩個具有公共類型的表達式。這裏沒有骰子。我知道沒有辦法有條件地返回類型基於運行時的比較。

你不得不類型有條件地轉發到不同的功能,通過引入剛剛那建立了Args...和簡單if聲明另一個輔助函數的方式:

template <size_t... Js> 
void fhelper (std::index_sequence<>, const std::set<int>& , std::index_sequence<Js...>) { 
    f(Js...); 
} 

template <std::size_t I, size_t... Is, size_t... Js> 
void fhelper (std::index_sequence<I, Is...>, const std::set<int>& set, std::index_sequence<Js...>) { 
    if (set.find(I) == set.end()) { 
     fhelper(std::index_sequence<Is...>{}, set, std::index_sequence<Js..., I>{}); 
    } 
    else { 
     fhelper(std::index_sequence<Is...>{}, set, std::index_sequence<Js...>{}); 
    } 
} 

int main() { 
    fhelper (std::make_index_sequence<10>{}, {1,3,7,8}, std::index_sequence<>{}); 
} 
+0

@ Barry對不起,但我簡化了這個問題,我更新了這個問題。我不確定你的技術是否仍然適用。 – prestokeys

+0

@prestokeys當然可以,只需要調用'f(std :: get (tuple)...)'而不是我想的。 – Barry

+0

@ Barry是的,我試過,並將其發佈在我的問題中,但它不編譯(超出邊界錯誤的元組索引)。雖然我認爲它可以修復。更新:固定。謝謝。 – prestokeys

0

我只是想分享解決我尋求的一般問題。 Barry對上述具體問題的解決方案使之成爲可能:

#include <iostream> 
#include <utility> 
#include <tuple> 

template <template <std::size_t, typename> class Check, typename F, size_t... Js, typename Tuple> 
void screenArguments (std::index_sequence<>, std::index_sequence<Js...>, const Tuple& tuple) { 
    F()(std::get<Js>(tuple)...); 
} 

template <template <std::size_t, typename> class Check, typename F, std::size_t I, size_t... Is, size_t... Js, typename Tuple> 
void screenArguments (std::index_sequence<I, Is...>, std::index_sequence<Js...>, const Tuple& tuple) { 
    if (Check<I, Tuple>::execute(tuple)) 
     screenArguments<Check, F>(std::index_sequence<Is...>{}, std::index_sequence<Js..., I>{}, tuple); 
    else 
     screenArguments<Check, F>(std::index_sequence<Is...>{}, std::index_sequence<Js...>{}, tuple); 
} 

template <template <std::size_t, typename> class Check, typename F, typename Tuple, std::size_t N = std::tuple_size<Tuple>::value> 
void passCertainArguments (const Tuple& tuple) { 
    screenArguments<Check, F> (std::make_index_sequence<N>{}, std::index_sequence<>{}, tuple); 
} 

// Testing 
#include <typeinfo> 

template <typename... Args> 
void foo (Args&&...) { 
    std::cout << sizeof...(Args) << " elements passed into foo.\n"; 
} 

struct Foo { 
    template <typename... Args> 
    void operator()(Args&&... args) { 
     foo(std::forward<Args>(args)...); 
    } 
}; 

template <typename... Args> 
void bar (Args&&...) { 
    std::cout << sizeof...(Args) << " elements passed into bar.\n"; 
} 

struct Bar { 
    template <typename... Args> 
    void operator()(Args&&... args) { 
     bar(std::forward<Args>(args)...); 
    } 
}; 

template <std::size_t N, typename Tuple> 
struct CheckArguments { 
    static bool execute (const Tuple& tuple) { 
     return std::get<N>(tuple) != std::get<N+1>(tuple); 
    } 
}; 

struct NullObject {}; 

template <std::size_t N, typename Tuple> 
struct CheckNotNullObject { 
    static bool execute (const Tuple& tuple) { 
     return typeid(std::get<N>(tuple)) != typeid(NullObject); 
    } 
}; 

template <typename F, typename... Args> 
void executeWithoutNullObject (Args&&... args) { 
    passCertainArguments<CheckNotNullObject, F> (std::forward_as_tuple(args...)); 
} 

template <typename F, typename... Args> 
void executeRemoveConsecutiveRepeatElements (Args&&... args) { 
    const auto tuple = std::forward_as_tuple(args...); 
    passCertainArguments<CheckArguments, F, decltype(tuple), sizeof...(Args) - 1> (tuple); 
} 

int main() { 
    executeWithoutNullObject<Foo> (3, 5, 'a', true, NullObject{}, 'b', 5.8, NullObject{}, NullObject{}, '!', 2); 
    // 8 elements passed into foo. (the 3 NullObjects are removed) 
    executeRemoveConsecutiveRepeatElements<Bar> (2, 1.5, 'a', 'a', true, 5, 5, false); 
    // 5 elements passed into bar. (the first 'a', the first 5, and 'false' removed) 
}