2014-10-29 94 views
1

我希望能夠使用不在我控制範圍內的變體類打包的參數調用任意函數(我們稱之爲blackbox)。我寫了一個函數模板unpack<T>,它從blackbox中提取需要專門用於目標類型的值。這適用於通過值傳遞的參數。但是,我不知道如何處理傳遞引用:如何將T轉發到以const&T爲參數的函數

#include <string> 
#include <functional> 
#include <iostream> 
#include <utility> 
#include <type_traits> 

/* Variant container */ 
struct blackbox 
{ 
    int int_value() const { return 42; } 
    bool bool_value() const { return true; } 
    std::string string_value() const { return "str"; } 
}; 

/* Unpack function templates */ 
template<typename T> 
T unpack(const blackbox &v) 
{ 
    static_assert(sizeof(T) == 0, "This template has to be specialized"); 
} 

template<> 
int unpack(const blackbox &v) 
{ 
    return v.int_value(); 
} 

template<> 
bool unpack(const blackbox &v) 
{ 
    return v.bool_value(); 
} 

template<> 
std::string unpack(const blackbox &v) 
{ 
    return v.string_value(); 
} 

/* Call function with arguments extracted from blackbox */ 
template<typename T> 
void call(std::function<void(T)> f, const blackbox &v) 
{ 
    f(unpack<T>(v)); 
} 

/* Sample functions */ 

void f_int(int i) { std::cout << "f_int(" << i << ")" << std::endl; } 
void f_bool(bool b) { std::cout << "f_bool(" << b << ")" << std::endl; } 
void f_str(std::string s) { std::cout << "f_str(" << s << ")" << std::endl; } 
void f_str_ref(const std::string &s) { std::cout << "f_str_ref(" << s << ")" << std::endl; } 


int main() 
{ 
    blackbox b; 

    // direct call 
    f_str_ref(b.string_value()); 

    // indirect call 
    call(std::function<void(int)>(f_int), b); 
    call(std::function<void(bool)>(f_bool), b); 
    call(std::function<void(std::string)>(f_str), b); 
    call(std::function<void(const std::string&)>(f_str_ref), b); //doesn't work 

    return 0; 
} 

我需要unpack專業化轉發std::string情況下受到充分const std::string&參數的函數。定義

template<> 
const std::string& unpack(const blackbox &v) 
{ 
    return v.string_value(); 
} 

顯然不起作用,因爲返回了對局部變量的引用。沒有爲const std::string&專門定義unpack會導致靜態斷言失敗。

理想情況下,unpack<std::string>應該用於const std::string&,但提供單獨的專業化就足夠了。

+2

你試過'f(unpack :: type>(v));'? – 2014-10-29 15:46:16

+0

謝謝,'std :: decay '是我正在尋找的。 – 2014-10-29 16:59:29

+0

@PiotrS。你的評論有資格作爲答案,我很樂意接受它。 – 2014-11-02 09:48:21

回答

1

你需要的是從<type_traits>std::decay<T>,去除CV -qualifiers和引用從給定類型(除非這是一個函數或數組類型):

static_assert(std::is_same<std::decay<const std::string&>::type, 
          std::string>::value, "!"); 

話雖這麼說,你可以使用以下語法:

f(unpack<typename std::decay<T>::type>(v)); 

使得[CV/&/&&] std::string類型的任何變化將評價爲純std::string

相關問題