2014-02-10 55 views
1

我有以下代碼:decltype和boost ::變種 - 檢索當前值

#include <boost/variant.hpp> 

#include <iostream> 
#include <string> 

boost::variant<int, double, std::string> variant; 

template <typename FirstArg, typename... OtherArgs> 
auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info)) 
{ 
    if (typeid(FirstArg) == variant_type_info) 
    { 
     return boost::get<FirstArg>(variant); 
    } 

    return bar<OtherArgs...>(variant_type_info); 
} 

template <typename... VariantArgs> 
auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type())) 
{ 
    return bar<VariantArgs...>(variant.type()); 
} 

int main() 
{ 
    variant = 0.5; 
    const auto& baz = foo(variant); 
    std::cout << baz << '\n'; 
} 

它給我以下錯誤:

main.cpp:9:135: error: 'bar' was not declared in this scope 

auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info)) 

                                    ^

main.cpp:9:148: error: expected primary-expression before '...' token 

auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info)) 

                                        ^

main.cpp:9:148: error: expected ')' before '...' token 

main.cpp:9:135: error: 'bar' was not declared in this scope 

auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info)) 

                                    ^

main.cpp:9:54: error: expected type-specifier before 'decltype' 

auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info)) 

                ^

main.cpp:9:54: error: expected initializer before 'decltype' 

main.cpp:20:69: error: 'bar' was not declared in this scope 

auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type())) 

                    ^

main.cpp:20:69: error: 'bar' was not declared in this scope 

main.cpp:20:84: error: expected primary-expression before '...' token 

auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type())) 

                        ^

main.cpp:20:84: error: expected ')' before '...' token 

main.cpp:20:69: error: 'bar' was not declared in this scope 

auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type())) 

                    ^

main.cpp:20:69: error: 'bar' was not declared in this scope 

main.cpp:20:60: error: expected type-specifier before 'decltype' 

auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type())) 

                  ^

main.cpp:20:60: error: expected initializer before 'decltype' 

main.cpp: In function 'int main()': 

main.cpp:28:34: error: 'foo' was not declared in this scope 

    const auto& baz = foo(variant); 

Coliru例子 - http://coliru.stacked-crooked.com/a/4467c33489b08359

我見我不能在decltype中引用相同的函數。有沒有解決這種情況的解決方法?我正在嘗試編寫函數以從boost :: variant對象中檢索當前值。

回答

2

是的,在一般情況下有一種解決方法。它被稱爲:

部分排序。爲了獲得前面的參考,將方法移動到類名稱空間中。

然而

沒有什麼可以節省你在這裏。除非在編譯時已經知道它,否則無法讓編譯器恢復參數的靜態類型。這應該是有點明顯的。

我的意思是,foo()應該返回什麼類型?它怎麼可能包含所有可能的元素類型?對。這就是爲什麼你有變種開始。

三種方式前進:

  1. 靜態知道類型:

    const auto& baz = boost::get<double>(variant); 
    
  2. 回報typeid的,而不是:

    std::type_info const& typeinfo_value = variant.type(); 
    
  3. 分支出來,並創建單獨的路徑來處理所有案例。 Boost有這種情況的static_visitor:

    struct Visitor : boost::static_visitor<std::string> { 
        std::string operator()(std::string const&) const { return "std::string"; } 
        std::string operator()(int) const { return "int"; } 
        std::string operator()(double) const { return "double"; } 
    
        template <typename... T> 
         std::string operator()(boost::variant<T...> const& v) const { 
          return boost::apply_visitor(*this, v); 
         } 
    }; 
    
    int main() 
    { 
        static const Visitor _visitor; 
    
        variant = 0.5f; 
        std::cout << "The actual type is " << _visitor(variant) << "\n"; 
    }