2017-06-01 86 views
-1

我想知道如何在不使用虚函数的情况下在C++中声明接口。经过一番互联网搜索我放在一起此解决方案:没有虚函数的C++接口

#include <type_traits> 

using namespace std; 

// Definition of a type trait to check if a class defines a member function "bool foo(bool)" 
template<typename T, typename = void> 
struct has_foo : false_type { }; 

template<typename T> 
struct has_foo<T, typename enable_if<is_same<bool, decltype(std::declval<T>().foo(bool()))>::value, void>::type> : true_type { }; 

// Definition of a type trait to check if a class defines a member function "void bar()"  
template<typename T, typename = void> 
struct has_bar : false_type { }; 

template<typename T> 
struct has_bar<T, typename enable_if<is_same<void, decltype(std::declval<T>().bar())>::value, void>::type> : true_type { }; 

// Class defining the interface 
template <typename T> 
class Interface{ 
public: 
    Interface(){ 
    static_assert(has_foo<T>::value == true, "member function foo not implemented"); 
    static_assert(has_bar<T>::value == true, "member function bar not implemented"); 
    } 
}; 

// Interface implementation 
class Implementation:Interface<Implementation>{ 
public: 
    // If the following member functions are not declared a compilation error is returned by the compiler 
    bool foo(bool in){return !in;} 
    void bar(){} 
}; 

int main(){} 

我打算在一个项目中,我将只使用静态多态性使用这种设计策略。 我将在该项目中使用的C++标准是C++ 11。

您认为这种方法的优缺点是什么?

对我提出的代码有什么改进?

编辑1: 我刚刚意识到,从接口继承是不需要的。此代码还可以用于:

class Implementation{ 
    Interface<Implementation> unused; 
public: 
    bool foo(bool in){return !in;} 
    void bar(){} 
}; 

编辑2-3: 的static_assert溶液(带或不带CRTP)和标准CRTP之间的一个主要区别是,CRTP不保证派生类实现所有接口成员。例如,下面的代码编译正确:

#include <type_traits> 
using namespace std; 

template< typename T> 
class Interface{ 
public: 
    bool foo(bool in){ 
    return static_cast<T*>(this)->foo(in); 
    } 
    void bar(){ 
    static_cast<T*>(this)->bar(); 
    } 
}; 

class Implementation: public Interface<Implementation>{ 
public: 
// bool foo(bool in){return !in;} 
// void bar(){} 
}; 

int main(){} 

关于丢失成员函数的错误将仅当将所需要的功能FOO酒吧编译器被返回。

我看到它的方式,static_assert解决方案比CRTP更像是一个接口声明。

+0

你看着[CRTP(https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)? – Amadeus

+0

@Amadeus是的,很久以前,但不幸的是我忘记了它... – carlo

+0

'class Implementation:Interface '。这是CRTP,没有别的。 CRTP是这个,没有别的。 'static_assert'是可选的,它们只提供更好的错误信息。 –

回答

1

看来你想实施concepts (lite)。您可能希望在尝试实施之前阅读文章。

如果缺少编译器支持,您可以部分实现此想法。您的static_assert想法是表达接口要求的已知方式。

考虑链接中的Sortable示例。你可以创建一个类模板Sortable,使用static_assert断言所有关于模板参数的想法。您向用户解释他们需要实施某些方法,并且为了强制执行该方案,他们需要以各种方式使用Sortable<TheirClass>

为了表达,在函数声明中正确。的想法,你的函数需要一个Sortable,你将不得不采取这样的事情:

template <typename Container> 
auto doSomethingWithSortable (Container&) -> std::enable_if<Implements<Container, Sortable>>::type; 
1

实现静态多态性的常用方法是使用CRTP

有了这个模式,你定义一个模板接口类,其方法转发到模板:

// Interface 
template <typename T> 
struct base { 
    void foo(int arg) { 
     static_cast<T*>(this)->do_foo(arg); 
    } 
}; 

您实现从基类继承并实现方法:

// Implementation 
struct derived : base<derived> { 
    void do_foo(int arg) { 
     std::cout << arg << '\n' 
    } 
}; 

这模式的优点是它看起来像常规的运行时多态性那样“感觉”,并且错误消息通常是相当理智的。因为所有的代码对编译器都是可见的,所以一切都可以内联,所以没有开销。

+0

很久以前,我遇到了CRTP,但完全忘了它......我编辑了我的问题,以添加使用我提议的方法的可能优势。 – carlo

+0

也许我原来的问题还不够清楚。我正在寻找的是一种声明界面的方法。与CRTP一起玩我发现与提议的解决方案有着重要的不同。请在我的问题中查看**编辑2 **。 – carlo