Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 执行特定函数取决于类型_C++ - Fatal编程技术网

C++ 执行特定函数取决于类型

C++ 执行特定函数取决于类型,c++,C++,我想做一个函数,它可以处理不同类型的事情,这取决于类型 我知道重载是一个很好的解决方案。就是 class C1 {...}; class C2 {...}; void handle(C1& c1){...} void handle(C2& c2){...} 但是,由于这两个初始化是相同的,所以有太多以重载方式重复的代码。这就是我想把它们包在一起的原因 我有一些想法。 比如说, class C1 {...}; class C2 {...}; void handle_C1

我想做一个函数,它可以处理不同类型的事情,这取决于类型

我知道重载是一个很好的解决方案。就是

class C1 {...};
class C2 {...};    
void handle(C1& c1){...}
void handle(C2& c2){...}
但是,由于这两个初始化是相同的,所以有太多以重载方式重复的代码。这就是我想把它们包在一起的原因

我有一些想法。 比如说,

class C1 {...};
class C2 {...};

void handle_C1(C1 &c1);
void handle_C2(C2 &c2);

template<typename T>
void handle(T &content){
// Initialization was done here
if (std::is_same(C1, T))
   handle_C1(content);
if (std::is_same(C2, T))
   handle_C2(content);
}
class C1{…};
C2类{…};
无效把手(C1和C1);
无效手柄(C2和C2);
模板
无效句柄(T和内容){
//初始化是在这里完成的
如果(标准::相同(C1,T))
手柄C1(内容);
如果(标准::相同(C2,T))
处理C2(内容);
}
发现编译错误,错误为句柄C2不匹配参数,因为调用时句柄C2参数类型为C2

C1 c1;
handle_C1<C1>(c1);
C1;
把手C1(C1);
<>根据C++中的sFIAE,我希望编译会忽略这个替换失败,但是它不。p> 有人能给我一个建议吗

超载的最佳解决方案是什么?如果这是真的,我如何减少重复的代码

用T实例化handle()时,将实例化函数的整个主体。这两个“如果”及其主体都被编译。虽然您和我都知道is_same()是一个编译时常量,您可能希望编译器忽略不可能的情况,但它的使用方式是作为运行时值,编译器必须处理ifs和语义检查,就像它们都可能被调用一样(即使优化器可以消除一个,那也是在编译器进行有效性测试之后。)因此,您最终得到了调用handle_C1和handle_C2的代码,它们都传递了相同的类型,其中一个肯定是无效的,无法编译

如果可以使用c++17,则有一个新功能直接解决此问题,称为“constexpr If”,如果constexpr为true,则会处理If的主体(有效语句和语法除外):

template<typename T>
void handle(T &content){
// Initialization was done here
if constexpr (std::is_same(C1, T))
   handle_C1(content);
else if constexpr (std::is_same(C2, T))
   handle_C2(content);
}
模板
无效句柄(T和内容){
//初始化是在这里完成的
如果constexpr(std::is_same(C1,T))
手柄C1(内容);
否则如果constexpr(std::与(C2,T)相同)
处理C2(内容);
}

如果你没有C++ 17编译器,(或者即使你这样做),你也应该考虑回到原来的设计,简单地从每个函数中初始化,使它成为一个通用的辅助函数。 如果您有多个类,这些类在许多情况下处理相同,但具有单独的字符,那么这可能需要一个基类。例如,您可以有如下内容:

class CBase { ... common features of C1, C2, C3, ... 
    public:
        ~CBase() {};
        virtual void handle() = 0;
};

class C1 : public CBase { ... something specific to C1
    public:
        virtual void handle() { do what has to be done for C1 }
};
class C2 : public CBase { ... something specific to C2
    public:
        virtual void handle() { do what has to be done for C2 }
};
现在,听起来这已经解决了这个问题,因为您可以调用C1.handle()或CBase->handle()。如果需要通过外部函数完成,可以执行以下操作:

void handle(CBase *base_ptr) {
    base_ptr->handle();
}
就我个人而言,无论如何,我觉得这比通过非常量引用传递要好,但我知道这是一场大辩论

关于您的SFINAE:
SFINAE只是说,如果模板替换失败,编译器将继续查找匹配项,而不会直接抛出错误。但如果根本找不到匹配项,它将抛出错误。在您的情况下,如果例如T=C2,它仍将尝试编译句柄_C1(C2),失败。(您的“if case”是一个运行时决策,而编译器在编译时做出这些决策)

在我看来,您似乎过度考虑了这个问题。只需在不使用初始化代码的情况下定义重载,并定义一个利用重载解析的
句柄
函数即可

class C1 {...};
class C2 {...};    
void handle_impl(C1& c1){...} // Remove initialization from your overloads
void handle_impl(C2& c2){...}

template<typename T>
void handle(T &content)
{
    // Initialization is done here

    // Let the compiler resolve overloads for you
    handle_impl(content);
}
class C1{…};
C2类{…};
void handle_impl(C1&C1){…}//从重载中删除初始化
无效句柄\u impl(C2&C2){…}
模板
无效句柄(T和内容)
{
//初始化在这里完成
//让编译器为您解决重载问题
处理(内容);
}

我认为在您的情况下,重载就是您所需要的。只需为您编写另一个特殊初始化方法来处理每个类,并在模板版本()中执行常规操作:

void handleSpecial(C1和C1){

std::cout您可以恢复到良好的旧指针别名。允许将指向某个类型的指针强制转换为指向另一个类型的指针,如果指向的值的类型不正确,则只需解除指针的防护

但是在这里,您知道在运行时类型是正确的,因为
std::is_same
保证了它

template<typename T>
void handle(T &content){

    // Initialization was done here
    if (std::is_same<C1, T>()) {
        C1* c = reinterpret_cast<C1*>(&content);
       handle_C1(*c);
    }
    if (std::is_same<C2, T>()) {
        C2* c = reinterpret_cast<C2*>(&content);
       handle_C2(*c);
    }
}
模板
无效句柄(T和内容){
//初始化是在这里完成的
if(std::is_same()){
C1*c=重新解释铸件和内容;
手柄C1(*c);
}
if(std::is_same()){
C2*c=重新解释铸件和内容;
手柄C2(*c);
}
}

它只需要一个真正聪明的优化编译器可以避免的自动指针分配和复制,因为在低级机器代码中,它显然是不可操作的。

下面是另一个解决方案,它只需将这两种行为共有的代码提取到自己的函数中:

class C1 { /* ... */ };
class C2 { /* ... */ };

template<typename T>
void handle_init(T& content) {
    // Common initialization code
}

void handle(C1& c1) {
    handle_init(c1);
    // C1-specific code
}

void handle(C2& c2) {
    handle_init(c2);
    // C2-specific code
}
C1类{/*…*/};
C2类{/*…*/};
模板
无效句柄初始化(T和内容){
//通用初始化代码
}
空心把手(C1和C1){
handle_init(c1);
//C1特定代码
}
空手柄(C2和C2){
句柄初始化(c2);
//C2特定代码
}
根据
handle\u init
中的代码,例如,如果函数体仅调用
content
的“getter”方法,则可能不需要模板,而可以事先调用这些方法,并通过
handle
函数传递给
handle\u init

我将这两个函数命名为
handle
,以与您提供的代码保持一致,但是您可以给它们不同的名称,并且它仍然适用于大多数用例。重载的大多数用法都是这样的,因为重载解析使用参数的编译时类型,作为程序员,您通常在invo中都知道这一点阳离子位点

一个大的例外是如果参数class C1 { /* ... */ }; class C2 { /* ... */ }; template<typename T> void handle_init(T& content) { // Common initialization code } void handle(C1& c1) { handle_init(c1); // C1-specific code } void handle(C2& c2) { handle_init(c2); // C2-specific code }