簡體   English   中英

模板返回 c++

[英]Template Return c++

我正在嘗試基於全局變量DOF在兩個 class 對象之間切換。 想法是使用模板 class 更改返回類型。 但是 main() 中的第一行有一個編譯時錯誤template argument deduction/substitution failed 你能幫我理解問題並解決它嗎?有沒有更好的方法呢? 任何建議和幫助表示贊賞。 提前致謝。

#include <iostream>
#include <string>

class MM
{
public:
    MM(){}
    std::string printName()
    {
        return "MM";
    }
};

class MM2
{
public:
    MM2(){}
    std::string printName()
    {
        return "MM2";
    }
};

using namespace std;
const unsigned short int DOF = 7;

MM* obj = nullptr;
MM2* obj2 = nullptr;

template<class T>
T getClass()
{
    if(DOF==7)
    {
        if(obj == nullptr)
        {
            obj = new MM();
        }
        return obj;
    }
    else if(DOF == 6)
    {
        if(obj2 == nullptr)
        {
            obj2 = new MM2();
        }
        return obj2;
    }
}

int main()
{

    getClass()->printName();
    //std::cout << "class name " << getClass()->printName() << std::endl;
    return 0;
}

這不是模板在 C++ 中的工作方式。 模板參數的類型必須在編譯時知道,並且不能在運行時更改。

您在示例掃描中嘗試實現的模式很容易通過虛擬函數完成:使MMMM2具有共同的基礎 class 並使printName成為虛擬 function。 雖然我們在這里:不要使用手動 memory 管理,即不要使用顯式的新建/刪除。 使用像unique_ptr這樣的智能指針。

其他選項是std::anystd:: variant但我不會推薦它們,除非你有一個非常特殊的用例。

對於您的簡單示例,一個選項可能是返回 function 指針或std::function 這將適用於您的示例,因為您的類是無狀態的,但我懷疑您的真實類具有 state 或您希望訪問的更多方法,在這種情況下您不應該嘗試這樣做。

如果您可以使用 C++17(如果您不能使用,那就太可惜了),如果您稍微切換一下,您就可以做到這一點。

首先,使用模板參數來確定getClass的作用並使用if constexpr而不是普通的if

template<int N>
auto getClass()
{
    if constexpr (N == 7)
    {
        if(obj == nullptr)
        {
            obj = new MM();
        }
        return obj;
    }
    else if constexpr (N == 6)
    {
        if(obj2 == nullptr)
        {
            obj2 = new MM2();
        }
        return obj2;
    }
}

然后像這樣調用這個模板:

std::cout << "class name " << getClass <DOF> ()->printName() << std::endl;

雜項說明:

  • 通過getClass的所有路徑都應該返回一個值。

  • 您通過調用new而不是調用delete來泄漏 memory 。 有更好的選擇。


編輯:這是使用 SFINAE 的 C++11 解決方案:

template<int N, typename std::enable_if<N == 7, int>::type = 0>
MM *getClass()
{
    if(obj == nullptr)
    {
        obj = new MM();
    }
    return obj;
}
    
template<int N, typename std::enable_if<N == 6, int>::type = 0>
MM2 *getClass()
{
    if(obj2 == nullptr)
    {
        obj2 = new MM2();
    }
    return obj2;
}

然后你仍然可以這樣做:

std::cout << "class name " << getClass <DOF> ()->printName() << std::endl;

現場演示

這是你可以嘗試的。 正如其他人所說,模板僅在編譯時起作用:如果您想稍后在運行時動態更改類型,那么多態是 go 的方法。 您可以使用一種“PIMPL”設計在 MM 和 MM2 類之上有效地“插入”一個基礎 class。 基礎 class 包含純虛函數,用於您需要訪問的 MM 和 MM2 的所有常用函數(例如,本例中的 printName())。

#include <iostream>
#include <memory>
#include <string>

class MM
{
public:
    MM() {}
    std::string printName()
    {
        return "MM";
    }
};

class MM2
{
public:
    MM2() {}
    std::string printName()
    {
        return "MM2";
    }
};

class MMBase
{
public:
    virtual std::string printName() = 0;
    virtual ~MMBase() {}
};

//Templated wrapper for each MM class type, deriving from abstract MMBase
template<class T>
class MMWrap : public MMBase
{
    std::unique_ptr<T> _impl;
public:
    MMWrap() : _impl(nullptr)
    {
        _impl = std::make_unique<T>();
    }

    //Pass function call to _impl pointer
    std::string printName()
    {
        return _impl->printName();
    }
};

class MMFactory
{
public:
    enum MMType {TypeMM2=6,TypeMM};
    static MMType _type;

    static std::unique_ptr<MMBase> getMM() 
    {
        if (_type == TypeMM) return std::unique_ptr<MMBase>(new MMWrap<MM>());
        if (_type == TypeMM2) return std::unique_ptr<MMBase>(new MMWrap<MM2>());
        return nullptr; //Avoids compiler warning about not all paths return value
    }
};

//Initialize static member to which default MM type is required
MMFactory::MMType MMFactory::_type = MMFactory::TypeMM;

int main()
{
    std::cout<< MMFactory::getMM()->printName() << std::endl;

    MMFactory::_type = MMFactory::TypeMM2;

    std::cout << MMFactory::getMM()->printName() << std::endl;
}

我已經放入了一個模板化的包裝器 class,但這可能需要根據 MM/MM2 構造函數需要的參數進行修改。 此外,包裝的指針是在構造函數中創建的(如果它們拋出則可能存在問題):這些可以移動到惰性求值 model,使 _impl 可變。 我不知道以后如何使用 MM/MM2:如果它們具有引用其他 MM 類型的函數,則可能需要做更多的工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM