2016-12-28 95 views
1

這是我的簡化代碼:模板雙模板類方法

template<typename device, template<typename device> class protocol> 
class MyClass 
{ 
public: 
    template<typename select> 
    bool method() 
    { 
    // Code 
    } 
}; 

我想method在類型方面作用不同。

換句話說,我有兩種不同的可能的協議,我希望根據協議對我的方法有兩種不同的行爲。但我不知道如何用模板編寫它。

回答

1

例如,使用SFINAE(如果你接受一個C++ 11溶液)

#include <iostream> 
#include <type_traits> 

template <typename> 
struct protocol_1 
{ }; 

template <typename> 
struct protocol_2 
{ }; 

template<typename device, template<typename> class protocol> 
class MyClass 
{ 
    public: 
     template<typename select, typename p = protocol<device>> 
     typename std::enable_if< 
     std::is_same<p, protocol_1<device>>::value, bool>::type 
     method() 
     { return true; } 

     template<typename select, typename p = protocol<device>> 
     typename std::enable_if< 
     std::is_same<p, protocol_2<device>>::value, bool>::type 
     method() 
     { return false; } 
}; 

int main() 
{ 
    MyClass<int, protocol_1> m1; 
    MyClass<int, protocol_2> m2; 

    std::cout << m1.method<int>() << std::endl; // print 1 (true) 
    std::cout << m2.method<void>() << std::endl; // print 0 (false) 
} 

---編輯---

正如指出的Yakk(感謝!),這解決方案很薄弱,因爲使用可以被顯式化和循環發佈的模板默認值。

一個例子;與

MyClass<int, protocol_1>{}.method<void>(); 

就叫method()的 「protocol_1」 版本,使用默認值p;但explciting p,如下

MyClass<int, protocol_1>{}.method<void, protocol_2<int>>(); 

被稱爲method()的「protocol_2」版本在MyClass的基礎上protocol_1

的istance爲了避免這個問題,有可能增加一個static_assert(),在這兩個版本的method() ,檢查和強加p等於默認值(protocol<device>

我的意思是......是遵循

template<typename select, typename p = protocol<device>> 
    typename std::enable_if< 
     std::is_same<p, protocol_1<device>>::value, bool>::type 
    method() 
    { 
    static_assert(std::is_same<p, protocol<device>>::value, "!"); 

    return true; 
    } 

    template<typename select, typename p = protocol<device>> 
    typename std::enable_if< 
    std::is_same<p, protocol_2<device>>::value, bool>::type 
    method() 
    { 
    static_assert(std::is_same<p, protocol<device>>::value, "!"); 

    return false; 
    } 

所以

MyClass<int, protocol_1>{}.method<void, protocol_2<int>>(); 

生成編譯器錯誤。

+3

請注意,這種方法是非常脆弱的,因爲如果在沒有人通過模板參數2的情況下,主體只有在有效的情況下才有效,那麼您將得到一個不良診斷需要的程序。更糟的是沒有編譯器會診斷問題;你的代碼看起來很完美。 – Yakk

+0

@skyp搜索「無需診斷」,標準中只有十幾個。有關模板的必須具有有效的專業化(這意味着標準中的內容與通俗不同) – Yakk

+0

@Yakk明白了。謝謝。 – skypjack

1

使用外部助手是另一種可能的解決方案:

template <typename T> 
struct B { 
}; 
template <template<typename> class protocol, typename select> 
struct helper { 
    static bool do_real() { 
     return true; 
    } 
}; 
template <typename select> 
struct helper<B, select> { 
    static bool do_real() { 
     return false; 
    } 
}; 
template<typename device, template<typename> class protocol> 
class MyClass 
{ 
public: 
    template<typename select> 
    bool method() 
    { 
    return helper<protocol, select>::do_real(); 
    } 
}; 

this

0

您可以部分專業類,是這樣的:

template<typename device, template<typename> class protocol> 
class MyClass; 

template <typename> struct protocole1 { /* ... */ }; 
template <typename> struct protocole2 { /* ... */ }; 

template<typename device> 
class MyClass<device, protocol1> 
{ 
public: 
    template<typename select> 
    bool method() 
    { 
    // Code for protocole1 
    } 
}; 

template<typename device> 
class MyClass<device, protocol2> 
{ 
public: 
    template<typename select> 
    bool method() 
    { 
    // Code for protocole2 
    } 
}; 
2

你沒有提到這是目標標準,所以我會盡力爲您提供所有季節的替代方案。


在C++ 11/14中,您可以使用標記調度和函數重載來做到這一點。
它遵循最小,工作示例:

#include<iostream> 

template<typename> struct protocol_a {}; 
template<typename> struct protocol_b {}; 

template<typename device, template<typename> class protocol> 
class MyClass { 
    template<template<typename> class> struct tag {}; 

    template<typename select> 
    bool method(tag<protocol_a>) { 
     std::cout << "protocol_a" << std::endl; 
     return true; 
    } 

    template<typename select> 
    bool method(tag<protocol_b>) { 
     std::cout << "protocol_b" << std::endl; 
     return false; 
    } 

public: 
    template<typename select> 
    bool method() { 
     return method<device>(tag<protocol>{}); 
    } 
}; 

int main() { 
    MyClass<int, protocol_a> mca; 
    mca.method<void>(); 
    MyClass<int, protocol_b> mcb; 
    mcb.method<void>(); 
} 

相當緊湊。它不需要額外的類,部分專業化或sfinae表達式。缺點(如果我們可以稱此爲缺點)是您有一個更多的間接級別。


在C++ 17中,您可以使用if constexpr來獲得相同的結果。
它遵循一個最小的,工作示例:

#include<type_traits> 
#include<iostream> 

template<typename> struct protocol_a {}; 
template<typename> struct protocol_b {}; 

template<typename device, template<typename> class protocol> 
class MyClass { 
public: 
    template<typename select> 
    bool method() { 
     if constexpr(std::is_same_v<protocol<device>, protocol_a<device>>) { 
      std::cout << "protocol_a" << std::endl; 
      return true; 
     } else if constexpr(std::is_same_v<protocol<device>, protocol_b<device>>) { 
      std::cout << "protocol_b" << std::endl; 
      return false; 
     } 
    } 
}; 

int main() { 
    MyClass<int, protocol_a> mca; 
    mca.method<void>(); 
    MyClass<int, protocol_b> mcb; 
    mcb.method<void>(); 
} 

更緊湊,但C++ 17不能是一種選擇。
看到它在wandbox上運行。