【问题标题】:Conditionally defining method for container class有条件地定义容器类的方法
【发布时间】:2021-05-29 19:18:08
【问题描述】:

是否可以(并且这是一个好主意)根据其元素的类型有条件地为某些容器类 (template<typename ThingType> class Container) 定义方法?在阅读了std::enable_if 之后,我首先认为这是可能的,但现在我不确定我是否理解。

以下是我的尝试(点击here 在ideone 上运行)。如果std::is_base_of<ThingBase, ThingType>::valuefalse,则不会定义p 的返回类型。我认为编译器只会实例化一个没有该方法的类的对象。但事实证明它无法编译。

还有其他工具可以完成这项工作吗?或者我应该写两个类似Container 的类,根据ThingType 是什么而有不同的行为?或者,这可能是一份专业化的工作。

#include <iostream>
#include <type_traits>
#include <vector>


class ThingBase {
public:
    virtual void printHi() = 0;
    
};

class Thing : public ThingBase
{
    void printHi(){
        std::cout << "hi\n";
    }   
};


template<typename ThingType>
class Container{
private:
    std::vector<ThingType> m_things;
public:

    typename std::enable_if<std::is_base_of<ThingBase, ThingType>::value>::type p()
    {
        m_things[0].printHi();
    };
};


int main() {
    
    //Container<Thing> stuff; // works!
    Container<int> stuff; // doesn't work :(
    
    return 0;
}

编辑:

编译器的错误信息是

prog.cpp: In instantiation of ‘class Container<int>’:
prog.cpp:36:17:   required from here
prog.cpp:26:78: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
  typename std::enable_if<std::is_base_of<ThingBase, ThingType>::value>::type p()

@StoryTeller - Unslander Monica我不打算重载这个方法。我希望最终用户只要它可用就可以使用它。这些p 方法中只有一个,并且应该只需要一个(相对简单的)签名。

【问题讨论】:

  • 通常最好在此处添加编译器错误消息。
  • 您寻求定义的方法是否意味着重载?会有多个p 吗?这个会有一个独特的签名吗?
  • 你仅限于 C++11 吗? C++20 有requires 可以方便地禁用不需要的方法。
  • @HolyBlackCat 听起来很棒,但我最好坚持使用 c++11
  • 对于“如何做标题中的问题”,请参阅C++ templates: conditionally enabled member function - Stack Overflow(尽管正如下面的答案指出的那样,在这种情况下没有必要)

标签: c++ c++11 templates inheritance


【解决方案1】:

我不打算重载这个方法。我希望最终用户只要它可用就可以使用它。这些 p 方法中只会有一个,并且应该只需要一个(相对简单的)签名。

这大大简化了练习。解决办法是……什么都不做。

void p() {
    m_things[0].printHi();
}

当一个类模板被隐式实例化时,只有成员函数的声明被实例化。在尝试使用该成员之前,不会实例化定义。

所以你不需要做任何特别的事情。不能用的时候再用就会报错。

如果您仍然希望确保可推导性,并在这种情况下产生描述性错误,您可以在成员函数体中添加static_assert。只需对条件使用is_base_of 测试,然后添加一个漂亮的字符串即可。

这是编写通用实用程序时的常用方法。另一方面,SFINAE 的主要目的是控制过载解决。但你不是在这里做的。

【讨论】:

  • 这适用于int,但是碰巧有printHi 但不是从ThingBase 派生的类型呢?至少这是我从“任何时候都有意义”和is_base_of 所假设的。
  • @cigien - “但是类型呢..” 它呢?如果 OP 不想要额外的通用性,他们可以静态断言,正如我所指出的。无论哪种方式,在这种情况下使用 SFINAE 对货物崇拜来说太过分了。
  • 哦,对了,你确实提到了static_assert。是的,我同意,enable_if 对这份工作来说太过分了。
猜你喜欢
  • 1970-01-01
  • 2021-08-08
  • 1970-01-01
  • 2021-03-06
  • 1970-01-01
  • 2013-05-01
  • 2019-11-02
  • 1970-01-01
  • 2010-12-02
相关资源
最近更新 更多