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

Aya*_*973 2 c++ templates

我正在学习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;
};
Run Code Online (Sandbox Code Playgroud)

使用时,我会执行以下操作:

uint32_t test = HybridType("50");
long double test2 = HybridType("50.0");
Run Code Online (Sandbox Code Playgroud)

但是当我编译它时,我收到了很多警告:

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
Run Code Online (Sandbox Code Playgroud)

我真的不明白为什么我有这些警告(编译器无法选择合适的类型),因为当我输出我的变量时,它们似乎有正确的值?

Mar*_*ica 7

你的问题是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);
}
Run Code Online (Sandbox Code Playgroud)

在编译器中,您可能会尝试从应该返回的函数返回long double uint32_t.当然,稍后在编译过程中,将优化到:

operator uint32_t() const {
    return std::stoul(internalStr);
}
Run Code Online (Sandbox Code Playgroud)

......但到那时,警告已经发出.

补丁可以是:

  • 编写您想要显式的每个强制转换操作符.(有关详细信息,请参阅R Sahu的答案.)这样做的优点是更简单,更少打字.
  • 编写没有定义的模板化强制转换操作符声明,然后为所需的每种类型编写显式特化.(有关详细信息,请参阅πάνταῥεῖ的答案.)此功能必须为您希望能够投射的每种类型创建一个运算符; 缺少的类型将是编译错误.这可能是一个优点(对范围等的更多控制),或者不利(更多代码),具体取决于您的应用程序.

formwerapproach的优势

  • 这就是你使用模板特化或标签调度的原因,它们都是在编译时选择的. (2认同)

πάν*_*ῥεῖ 5

模板在编译时进行评估,因此您不能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. ...
Run Code Online (Sandbox Code Playgroud)