2014-02-26 25 views
4
中定義的類/名稱空間的位置

此代碼編譯時沒有任何警告或錯誤,並且是可執行的。現在讓C++推導一個參數在

template<class T> 
struct testclass 
{ 
    template<int I> 
    class inner {}; 
    template<int I> 
    void f(inner<I>) {} 
}; 

int main() 
{ 
    testclass<bool> test; 
    test.f(testclass<bool>::inner<3>()); // l. 13 
    return 0; 
} 

,我想要做的是省略testclass::第13行:

test.f(inner<3>()); 

它不工作。有什麼我可以添加在testclass的定義,以便我的代碼工作?

C++ 11是允許的。

+1

你可以寫'decltype(測試)::內<3>'。您也可以將該函數的參數作爲模板參數'test.f <3>()'提供。 – dyp

回答

3

首先,樣板。

指數樣板:

template<unsigned... Is> struct indexes {typedef indexes<Is...> type;}; 
template<unsigned Max, unsigned... Is> struct make_indexes:make_indexes<Max-1, Max-1, Is...> {}; 
template<unsigned... Is> struct make_indexes<0, Is...>:indexes<Is...> {}; 

一個輔助類,允許代理建設不點名封閉類:

template<int I, typename... Args> 
struct inner_helper { 
    std::tuple<Args...> args; 
    template<typename T, unsigned... Is> 
    T construct(indexes<Is...>) && { 
    return { std::forward<Args>(std::get<Is>(args))... }; 
    } 
    template<typename T> 
    T construct() && { 
    return std::move(*this).template construct<T>(make_indexes<sizeof...(Args)>()); 
    } 
}; 

一個輔助功能,給你你想要的語法。需要注意的是,現在inner<3>是一個函數調用,而不是封閉類範圍之外創建一個對象:

template<int I, typename... Args> 
inner_helper<I, Args...> inner(Args&&... args) { 
    return {std::forward<Args>(args)...}; 
} 

我們有兩個重載增加testclass。一個需要一個inner_helper<int, Args...>並使用Args...構建一個inner<int>,其他需要inner<int>

template<class T> 
struct testclass 
{ 
    template<int I> 
    class inner {}; 
    template<int I> 
    void f(inner<I>) {} 
    template<int I, typename... Args> 
    void f(inner_helper<I, Args...> h) { 
    return f(std::move(h).template construct<inner<I>>()); 
    } 
}; 

最後,所要求的語法在使用點:

int main() 
{ 
    testclass<bool> test; 
    test.f(inner<3>()); // l. 13 
    return 0; 
} 

這可以讓你做你想做的語法(inner<3>()),支持使用任意參數構建所述inner<3>(這些參數可以完美轉發),並調用實際的f(inner<I>)方法。

它確實需要inner<I>是可移動構造的並且可以從參數到inner<I>隱含構造。

我假設inner<I>比上面使用的類型複雜一點。如果它不是更復雜的話,你應該考慮C++迭代器的SCARY技術,其中迭代器(而內部類型排序)實際上是一個外部類型。

live example

+0

這完全回答了我的問題。謝謝! – Johannes

+0

@Johannes哦,'std :: tuple '可以替換爲'std :: tuple ',但這有點危險(終身擴展問題)。只要類型涉及到廉價的''移動','std :: tuple '是一個優越的選擇。 – Yakk

7

一般來說,沒有全局編譯器標誌允許這樣的推導,因爲那樣會打敗名稱範圍。

但是,您可以在類外鍵入typedef(或者在模板的情況下 - 具有類型別名)。在你的情況將是:

template <int I> using inner = testclass::inner<I>; 

這已被寫入在全局命名空間,而不是內部的testclass

注意,模板別名的C++ 11

+0

謝謝,但在我的情況下,testclass是一個模板類,所以這沒有幫助。 – Johannes

+3

如果testclass本身就是一個模板,那麼你爲什麼不在問題中這麼說? – CygnusX1

+0

它可以很容易地適應 – bolov

2

功能不能省略testclass::,因爲inner是內部類的TestClass類的。

你可以做的是改變f功能的簽名,使其簡單一點:

struct testclass 
{ 
    template<int I> 
    class inner {}; 

    template<int I> 
    void f1() { 
     inner<I> obj; 
    } 
    template<typename T> 
    void f2(T&&) 
    { 
    } 
}; 

int main() 
{ 
    testclass test; 
    test.f1<3>(); 
    test.f2(testclass::inner<3>()); 
}