【问题标题】:C++ typedef to rename functionsC++ typedef 重命名函数
【发布时间】:2014-10-09 13:55:12
【问题描述】:

我希望能够typedef 函数,以便能够将模板元编程用作函数选择器(如下例所示)。我也尝试将函数作为模板参数传递。在这两种情况下都会出现错误,因为函数不是types。我知道如果它们是函子,这些方法中的任何一种都可以工作,但我希望能够有一个通用的解决方案。

是否有“typedef 函数”的实际方法,但名称不同,我只是不知道?

编辑:

此时我的用例是我希望能够在使用 boost::property_tree::xml_parser::read_xmlboost::property_tree::json_parser::read_json 之间进行选择。但不仅限于这种情况,使用成员函数、函数指针或std::function 将需要找到所有确切的函数定义并将其复制到正确创建一个选择器。

描述用例的更一般的方法是使用typedef double my_float,以便以后只需一次编辑即可更改所有代码。或者,更高级的是,typedef 可以在元程序选择器中定义。

void foo1() { /*do stuff*/ }
void foo2() { /*do other stuff*/ }

template <bool SELECT>
struct Selector {
    typedef foo1 foo;
};

template <>
struct Selector<false> {
    typedef foo2 foo;
};

【问题讨论】:

  • 如果我理解你想要做什么,只要有一个调用它的成员函数。
  • 您可能想查看 std::function 和 std::bind,因为我认为您实际上并不是在这里寻找 typedef / type 别名。
  • @chris 这将要求成员函数具有匹配的类型签名。对于 boost/STL 中的一些重模板化/重载的函数,很难做到正确。
  • @JohnSmith,好吧,我想我没抓住重点。
  • A typedef 需要一个函数是一个类型,但它不是 - 就像 2"foo" 不是类型一样。

标签: c++ function templates typedef template-meta-programming


【解决方案1】:

另外几个解决方案:

1) C++03解决方案:常量静态函数指针作为类模板的成员

typedef void (*Foo)();

template <bool>
struct Selector
{
    static const Foo foo;
};

template <bool select>
const Foo Selector<select>::foo = foo1;

template <>
const Foo Selector<false>::foo = foo2;

// ...

Selector<true>::foo();
Selector<false>::foo();

Live example.

2) C++11解决方案:常量静态auto类模板成员

template <bool>
struct Selector
{
    static constexpr auto foo = foo1;
};

template <>
struct Selector<false>
{
    static constexpr auto foo = foo2;
};

// ...

Selector<true>::foo();
Selector<false>::foo();

Live example.

3) C++14解决方案:auto变量模板

template <bool>
constexpr auto foo = nullptr;

template <>
constexpr auto foo<true> = foo1;

template <>
constexpr auto foo<false> = foo2;

// ...

foo<true>();
foo<false>();

Live example.

【讨论】:

【解决方案2】:

我假设您的目标只是根据一些bool 选择函数。您可以使用成员函数轻松做到这一点:

template <bool select>
struct selector {
    void operator () () {foo1();}
};

template <>
struct selector <false> {
    void operator () () {foo2();}
};

您当然可以使用int 参数和相同的技术在两个以上的函数之间切换。然后,您可以将此struct 作为参数传递给任何期望与foo1 具有相同签名的函数的函数。 (Live)

【讨论】:

  • 谢谢,这会奏效。正如我在 cmets 中提到的,问题在于一些重载的 Boost/STL 函数
【解决方案3】:

你可以:

1)使用成员函数

void foo1() { std::cout << "foo1\n"; }
void foo2() { std::cout << "foo2\n"; }

template <bool SELECT>
struct Selector {
    void foo() { foo1(); };
};

template <>
struct Selector<false> {
    void foo() { foo2(); };
};

int main() {

  Selector<true> s1t;
  Selector<false> s1f;

  s1t.foo();
  s1f.foo();
}

2) 使用通用函数包装器,例如std::function

void foo1() { std::cout << "foo1\n"; }
void foo2() { std::cout << "foo2\n"; }

template <bool SELECT>
struct Selector2 {
    std::function<void(void)> foo = foo1;
};

template <>
struct Selector2<false> {
    std::function<void(void)> foo = foo2;
};

int main() {

  Selector2<true> s2t;
  Selector2<false> s2f;

  s2t.foo();
  s2f.foo();

  return 0;
}

Live demo

【讨论】:

  • 谢谢,这会奏效。正如我在 cmets 中提到的,问题在于一些重载的 Boost/STL 函数。
  • 什么是“问题出在一些重载的 Boost/STL 函数上”?恕我直言std::function 解决方案非常优雅和灵活。无论如何,您都应该有一个固定的(或使用默认值的最小)函数签名来调用它。
  • boost.org/doc/libs/1_56_0/doc/html/property_tree/… read_xml 就是一个例子。它只有两个重载,但有很多参数。 std::function 或成员函数必须具有正确的函数签名才能正确映射这些。
  • 请添加您需要的示例!要调用函数,您必须知道传递参数的签名。或者你需要一个通用地图(比如 Qt QVariantMap 类)
  • @JohnSmith 我同意 MassimoCosta 的观点:您应该通过编辑来重新指定您的问题,可能使用更多代码和用例,以获得更准确的答案。
猜你喜欢
  • 2011-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-06
  • 2013-07-17
相关资源
最近更新 更多