2014-03-27 56 views
3

我正在编写一个库,我希望仅保留标题。在代码中,我有这样的事情:函数对象与仅包含标题的库中的函数

// Wrapper.h 
#ifndef INCLUDED_WRAPPER_H 
#define INCLUDED_WRAPPER_H 

namespace quux { 

template <typename T, typename U> 
class Wrapper 
{ 
    T m_t; 
    U m_u; 
public: 
    Wrapper(T const & t, U const & u) : m_t(t), m_u(u) { } 

    // ... 
}; 

} // namespace quux 

#endif // INCLUDED_WRAPPER_H 

// Foo.h 
#ifndef INCLUDED_FOO_H 
#define INCLUDED_FOO_H 

#include <type_traits> 

#include "Wrapper.h" 

namespace quux { 

// if some type is special, then there will be a specialization of this 
// struct derived from std::true_type 
template <typename T> struct is_special : std::false_type { }; 

class Foo 
{ 
    template <typename T> 
    Wrapper<Foo, T> impl(T const & t, std::true_type) const 
    { 
    return Wrapper<Foo, T>(*this, t); 
    } 

    template <typename T> 
    T const & impl(T const & t, std::false_type) const; 
    { 
    return t; 
    } 
public: 

    template <typename T> 
    auto operator()(T const & t) const // using automatic return type deduction 
    { 
    return impl(t, is_special<T>()); 
    } 

}; 

#if 1 
Foo const foo; 
#else 
template <typename T> 
auto foo(T const & t) // using automatic return type deduction 
{ 
    return Foo()(t); 
} 
#endif 

} // namespace quux 

#endif // INCLUDED_FOO_H 

我看到两种不同的方式有一个可调用实体名称为“QUUX :: foo”的:一个常量对象名为foo(在#if 1 - 分支)或一个名为foo的函数将其参数转发给Foo对象(#else-branch)。我应该选择哪个版本? const对象具有内部链接,因此如果标题包含在多个翻译单元中,则不存在链接器错误。这两种方法之间有什么显着差异?

回答

0

当你正在调用一个函数,并且你的函数对象没有状态时,我会使用函数接口。

首先,因为函数可以被重载,而函数对象不能在函数对象的主体之外。您可能希望为您的功能启用ADL扩展。

其次是因为函数对象更为奇怪。例如,它们不能转换为函数指针(在你的情况下没有很好的理由)(注意你可以用更多的样板来修复)。当简单的解决方案不足时,奇怪的解决方案只是一个好主意:在这种情况下,简单的完美转发功能更简单。

最后,您可能希望使函数完美向前,并让T&& rvalues提供返回T在最外层API级别的函数。这使得临时对象的生命周期延长能够通过你的功能。