簡體   English   中英

C ++模板:按類型返回值

[英]C++ templates: return value by type

我正在學習C ++和模板來實現一個配置文件閱讀器( http://www.adp-gmbh.ch/cpp/chameleon.html ),我正在嘗試為一個帶有std::string的類創建一個模板作為內部存儲,在將其賦值給變量時可以返回其內部值(double,long double,float,string,uint16_t,uint32_t)。

平台:Win10與Visual Studio社區2015 Update 1

class HybridType {
public:
    HybridType() {};
    explicit HybridType(const std::string& value) : internalStr(value) {}
    explicit HybridType(const char* value) : internalStr (std::string(value)) { }

    template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
    explicit HybridType(T numericValue) {
        std::stringstream strstr;
        strstr << std::setprecision(std::numeric_limits<T>::digits10 + 1) << numericValue;
        internalStr = strstr.str();
    }

    operator std::string() const { return internalStr; }

    template<typename T>
    operator T() const {
        if (std::is_same<T, std::uint16_t>::value) return std::stoi(internalStr);
        if (std::is_same<T, std::uint32_t>::value) return std::stoul(internalStr);
        if (std::is_same<T, std::uint64_t>::value) return std::stoul(internalStr);
        if (std::is_same<T, double>::value) return std::stod(internalStr);
        if (std::is_same<T, long double>::value) return std::stold(internalStr);
        if (std::is_same<T, float>::value) return std::stof(internalStr);
        return std::stoll(internalStr);
    }



    template<typename T> operator T*() { return internalStr.c_str(); }

private:
    std::string internalStr;
};

使用時,我會執行以下操作:

uint32_t test = HybridType("50");
long double test2 = HybridType("50.0");

但是當我編譯它時,我收到了很多警告:

1> warning C4244: 'return': conversion from 'double' to 'uint32_t',
possible loss of data 1>  see reference to function template
instantiation 'HybridType::operator T(void) const<uint32_t>' being
compiled 1>          with 1>          [ 1>              T=uint32_t 1> ] 
1> warning C4244: 'return': conversion from 'long double' to
'uint32_t', possible loss of data 1> warning C4244: 'return':
conversion from 'float' to 'uint32_t', possible loss of data 1>
warning C4244: 'return': conversion from '__int64' to 'uint32_t',
possible loss of data

我真的不明白為什么我有這些警告(編譯器無法選擇合適的類型),因為當我輸出我的變量時,它們似乎有正確的值?

你的問題是operator T() 從編譯器的角度來看它。 如果您展開uint32_t您會得到:

operator uint32_t() const {
    if (...) return std::stoi(internalStr);
    if (...) return std::stoul(internalStr);
    if (...) return std::stoul(internalStr);
    if (...) return std::stod(internalStr);
    if (...) return std::stold(internalStr);   // Consider here
    if (...) return std::stof(internalStr);
    return std::stoll(internalStr);
}

在編譯器中,您可能會嘗試從應該返回uint32_t的函數返回long double。 當然,稍后在編譯過程中,將優化到:

operator uint32_t() const {
    return std::stoul(internalStr);
}

......但到那時,警告已經發出。

修復是:

  • 編寫您想要顯式的每個強制轉換操作符。 (有關詳細信息,請參閱R Sahu的答案 。)這樣做的優點是更簡單,更少打字。
  • 編寫沒有定義的模板化強制轉換操作符聲明,然后為所需的每種類型編寫顯式特化。 (有關詳細信息,請參閱πάνταῥεῖ的答案 。)此功能必須為您希望能夠投射的每種類型創建一個運算符; 缺少的類型將是編譯錯誤。 這可能是一個優點(對范圍等的更多控制),或者不利(更多代碼),具體取決於您的應用程序。

formwerapproach的優勢

模板在編譯時進行評估,因此您不能使用if()在運行時選擇適當的轉換函數(返回類型會發生沖突,因此會出現警告)。

您需要為您的強制轉換運算符提供類型專用實現:

class HybridType {
public:
    // ...
    template<typename T>
    operator T() const {
        static_assert(std::is_same<T, std::uint16_t>::value ||
                      std::is_same<T, std::uint32_t>::value 
                      // ...
                     ,"Casted to an unsupported type!");
    }
    // ...
};

template<>
HybridType::operator std::uint16_t() const {
    return std::stoi(internalStr);
}

template<>
HybridType::operator std::uint32_t() const {
    return std::stoul(internalStr);
}

// aso. ...

Martin Booner的回答已經指出了核心問題。 我將為您想要在課堂上完成的內容提出一個更簡單的解決方案。

僅當實現是通用的時,才能使用類和函數模板。 在你的情況下,這不是真的。 返回int邏輯與返回double邏輯不同。 使用成員函數模板不是模板的最佳用途。

template<typename T>
operator T() const {
    if (std::is_same<T, std::uint16_t>::value) return std::stoi(internalStr);
    if (std::is_same<T, std::uint32_t>::value) return std::stoul(internalStr);
    if (std::is_same<T, std::uint64_t>::value) return std::stoul(internalStr);
    if (std::is_same<T, double>::value) return std::stod(internalStr);
    if (std::is_same<T, long double>::value) return std::stold(internalStr);
    if (std::is_same<T, float>::value) return std::stof(internalStr);
    return std::stoll(internalStr);
}

並不比任何簡單:

operator std::uint16_t() const {
    return std::stoi(internalStr);
}

operator std::uint32_t() const {
    return std::stoul(internalStr);
}

operator std::uint64_t() const {
    return std::stoul(internalStr);
}

operator double() const {
    return std::stod(internalStr);
}

operator long double() const {
    return std::stold(internalStr);
}

operator float() const {
    return std::stof(internalStr);
}

operator long long() const {
    return std::stoll(internalStr);
}

即使后者由於存在更多功能而更加冗長。

暫無
暫無

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

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