C++ 容器类的条件定义方法

C++ 容器类的条件定义方法,c++,c++11,templates,inheritance,C++,C++11,Templates,Inheritance,根据容器类的元素类型,有条件地为某些容器类(template-class-container)定义方法是否可能(也是一个好主意)?在阅读了std::enable_if之后,我最初认为这是可能的,但现在我不确定我是否理解了 下面是我的尝试(单击在ideone上运行)。如果std::is_base_of::value为false,则不会定义p的返回类型。我想编译器只会实例化一个类的对象,而不使用该方法。但事实证明它没有编译 这项工作还有别的工具吗?或者我应该编写两个类似于容器的类,它们根据Thing

根据容器类的元素类型,有条件地为某些容器类(
template-class-container
)定义方法是否可能(也是一个好主意)?在阅读了
std::enable_if
之后,我最初认为这是可能的,但现在我不确定我是否理解了

下面是我的尝试(单击在ideone上运行)。如果
std::is_base_of::value
false
,则不会定义
p
的返回类型。我想编译器只会实例化一个类的对象,而不使用该方法。但事实证明它没有编译

这项工作还有别的工具吗?或者我应该编写两个类似于容器的类,它们根据
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;
}
#包括
#包括
#包括
类库{
公众:
虚空printHi()=0;
};
类事物:公共事物库
{
void printHi(){
标准::cout
我不希望此方法被重载。我希望最终用户只要有意义就可以使用它。这些p方法中只有一个,并且应该只需要一个(相对简单的)签名

这大大简化了练习。解决办法是…不做任何特别的事情

void p() {
    m_things[0].printHi();
}
当一个类模板被隐式实例化时,只有成员函数的声明会随之实例化。在尝试使用该成员之前,定义不会被实例化

所以你不需要做任何特殊的事情。如果在无法使用时使用它,就会发生错误

如果仍然希望确保可派生性,并在这种情况下产生描述性错误,则可以向成员函数体添加一个
static\u assert

这是编写泛型实用程序时常用的方法。另一方面,SFINAE的主要目的是控制过载解决方案。但您在这里没有这样做

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

这大大简化了练习。解决办法是…不做任何特别的事情

void p() {
    m_things[0].printHi();
}
当一个类模板被隐式实例化时,只有成员函数的声明会随之实例化。在尝试使用该成员之前,定义不会被实例化

所以你不需要做任何特殊的事情。如果在无法使用时使用它,就会发生错误

如果仍然希望确保可派生性,并在这种情况下产生描述性错误,则可以向成员函数体添加一个
static\u assert


这是编写泛型实用程序时常用的方法。另一方面,SFINAE的主要目的是控制重载解析。但您不是在这里这样做。

通常最好在此处添加编译器错误消息。您试图定义的方法是否意味着重载?是否会有多个
p
这一个有唯一的签名?您是否仅限于C++11?C++20有
要求
,可以方便地禁用不需要的方法。@HolyBlackCat这听起来非常棒,但我最好还是坚持使用C++11。一般来说,在这里添加编译器错误消息是一个好主意。您试图定义的方法是否意味着要重载?会有吗不止一个
p
?这一个是否有唯一的签名?您是否仅限于C++11?C++20有
要求
,可以方便地禁用不需要的方法。@HolyBlackCat这听起来非常棒,但我最好还是坚持使用C++11这适用于
int
,但对于碰巧有
printHi
但不是从
ThingBase
派生出来的?至少这是我在“任何有意义的时候”中假设的,
@cigien的\u base-“但是类型呢…”那怎么办?如果OP不想要额外的泛型,他们可以静态断言,正如我指出的那样。不管怎样,在这种情况下使用SFINAE都太像货物崇拜了。哦,对了,你确实提到了
静态断言
。是的,我同意,
启用(如果
)对于这项工作来说太过分了。这对
int
有效,但是什么呢关于一个恰巧有一个
printHi
但不是从
ThingBase
派生出来的类型?至少这是我在“任何有意义的时候”中假设的,
@cigien的基础-“但是类型呢…”那怎么办?如果OP不想要额外的泛型,他们可以静态断言,正如我所指出的。不管怎样,在这种情况下使用SFINAE都太接近于货物崇拜。哦,对了,你确实提到了
static\u assert
。是的,我同意,
enable\u If
对于这项工作来说太过分了。