【问题标题】:template with duck typing in C++用 C++ 输入鸭子的模板
【发布时间】:2012-06-29 23:53:47
【问题描述】:

有没有办法要求模板类型具有属性?

例如:

template <typename T, typename U>
void foo()
{
    U a,b;
    bool truthiness = T()(a,b);
    if (truthiness)
        // do something
}

那么,我如何要求 T 定义 operator()(U a, U b) 并返回特定类型?这可能吗? (我知道它在 d 中,但我不确定 c++)。

ps。如果此处的鸭子打字有误,请告诉我,我相信它是正确的,但我不确定。

【问题讨论】:

  • 问题是,如果它没有有那个操作符,你想发生什么?抛开语法错误不谈,你会得到一个编译器错误——你还想要什么?
  • 这(部分)是concepts 应该提供的——一种直接指定对可以实例化模板的类型的要求的方法。不幸的是,尽管做了很多工作,它并没有成为标准。
  • 查找 SFINAE,这是一种专门为此目的而设计的技术。
  • 如果你想要的是类型T来实现operator()(int,int),语法错误,因为operator()必须应用于类型的实例,而不是类型本身(即@ 987654328@)
  • @MooingDuck:谢谢!这正是我感兴趣的。我还修复了错误,并使其更普遍。

标签: c++ templates duck-typing


【解决方案1】:

考虑到您的意图,您的语法是错误的。由于T 是一个类型,T(1, 2) 将使用双参数构造函数构造一个T 类型的临时对象。如果你想打电话给Ts 运营商(),你必须 вo 类似

T()(1, 2);

假设通过临时工程为您拨打电话。

如果T 没有这样的运算符(),则代码将无法编译。我实际上会说模板代码的一大好处是,只要语法有效(即您正在谈论的鸭式打字)它就“工作”,即无需通过要求 @ 来进一步限制它987654330@出席。

当然,在我的示例中它实际上可能有意义,因为对于T = void (*)(int, int),代码在语法上是有效的,但会导致通过空指针调用函数。但同样,这是特定于我的代码版本的,我不知道您要将运算符 () 应用于哪个特定类型的 T 对象。

话虽如此,但 Boost 库有很多功能可以检查这些属性并将它们用于模板元编程和/或静态断言中的分支,这毫无价值。

【讨论】:

  • 谢谢,我正在研究 boost 库。如果您能回答更一般的问题,我已经稍微编辑了这个问题。
  • @AndrewSpott:我不确定 boost 是否提供了解决方案,但 this 提供了一个接近的解决方案。请注意,如果 operator() 是私有的,C++03 解决方案将无法编译,因为 SFINAE 不能用于检测可访问性。
【解决方案2】:

通过简单地表达模板,你需要 T 有operator()(int, int)。如果没有,它将不会编译。

但是,如果您正在创建 API 并希望通知 API 的用户他们传递了不兼容的类型,那么您需要创建一个类型特征来检测运算符,并且您可以专门化函数来区分该事实并创建一个 static_assert 来表明事实。

【讨论】:

  • 这是游戏开始的地方。模板要求的条件是not存在operator()(int, int),条件是表达式T(1,2)有效(其实应该是T()(1,2)或类似的,我认为有错误在题)。例如,拥有operator()(long, long) 就足够了。您需要决定要执行什么以及为什么要执行,但是通常根据所需的表达式记录是要走的路,而不是根据您认为某人可能实现的功能来实现这些表达式有效。
【解决方案3】:

如果您可以访问 decltype,则可以相对轻松地进行自己的检查。

template <class T, class U> class check_same_type_t;

template <class T> class check_same_type_t<T, T> { };

template <class T, class U>
void foo()
{
    U a,b;
    check_same_type_t<bool, decltype(T()(a, b))> check;
    bool truthiness = T()(a,b);
    if (truthiness) ;
        // do something
}

启用以下功能:

struct A {
    bool operator()(int, int) { return true; }
};

struct B {
    int operator()(int, int) { return 1; }
};

int
main()
{
    foo<A, int>(); // will compile
    foo<B, int>(); // won't compile

}

只要确保这是您真正想要的。 强制泛型算法使用特定类型可能会反过来咬你。如果一个类型可以隐式转换为 bool,为什么在你的条件下使用它不令人满意?

【讨论】:

    猜你喜欢
    • 2013-05-10
    • 2011-09-16
    • 2011-05-25
    • 2011-10-18
    • 1970-01-01
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多