函数对象与仅标题库中的函数

时间:2014-03-27 16:12:03

标签: c++11

我正在写一个我想保留标题的库。在代码中我有这样的东西:

// 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 - branch)或一个名为foo的函数,它将其参数转发给一个Foo对象(#else-branch)。我更喜欢哪个版本? const对象具有内部链接,因此如果标头包含在多个转换单元中,则不会出现链接器错误。这两种方法之间是否存在显着差异?

1 个答案:

答案 0 :(得分:0)

在调用函数时,函数对象没有状态,我会使用函数接口。

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

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

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