简体   繁体   English

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

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

I'm learning C++ and templates to implement a configuration file reader ( http://www.adp-gmbh.ch/cpp/chameleon.html ) and I'm trying to make a template for a class with a std::string as internal storage, which can return its internal value when assigning it to a variable (double, long double, float, string, uint16_t, uint32_t). 我正在学习C ++和模板来实现一个配置文件阅读器( http://www.adp-gmbh.ch/cpp/chameleon.html ),我正在尝试为一个带有std::string的类创建一个模板作为内部存储,在将其赋值给变量时可以返回其内部值(double,long double,float,string,uint16_t,uint32_t)。

Platform: Win10 with Visual Studio Community 2015 Update 1 平台: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;
};

When using it, I do the following: 使用时,我会执行以下操作:

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

But when I compile this, I get a lot of warnings: 但是当我编译它时,我收到了很多警告:

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

I didn't really understand why I have these warnings (compiler cannot choose the appropriate type), because when I output my variables they seem to have the correct value? 我真的不明白为什么我有这些警告(编译器无法选择合适的类型),因为当我输出我的变量时,它们似乎有正确的值?

Your problem is operator T() . 你的问题是operator T() Look at it from the compiler's point of view. 从编译器的角度来看它。 If you expand for uint32_t you get: 如果您展开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);
}

Which looks to the compiler that you might be trying to return a long double from a function that is supposed to return uint32_t . 在编译器中,您可能会尝试从应该返回uint32_t的函数返回long double。 Of course, later on in the compilation process, that will get optimized down to: 当然,稍后在编译过程中,将优化到:

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

... but by that time, the warning has been issued. ......但到那时,警告已经发出。

The fix is either: 修复是:

  • Write each cast operator that you want explicitly. 编写您想要显式的每个强制转换操作符。 (See R Sahu's answer for details.) This has the advantage of being simpler and less typing. (有关详细信息,请参阅R Sahu的答案 。)这样做的优点是更简单,更少打字。
  • Write a templated cast operator declaration without a definition, and then write explicit specializations for each type that you want. 编写没有定义的模板化强制转换操作符声明,然后为所需的每种类型编写显式特化。 (See πάντα ῥεῖ's answer for details.) This has the feature that you must create an operator for every type you want to be able tot cast too; (有关详细信息,请参阅πάνταῥεῖ的答案 。)此功能必须为您希望能够投射的每种类型创建一个运算符; a missing type will be a compilation error. 缺少的类型将是编译错误。 This may be an advantage (more control on range etc), or a disadvantage (more code) depending on your application. 这可能是一个优点(对范围等的更多控制),或者不利(更多代码),具体取决于您的应用程序。

The advantage of the formwerapproach formwerapproach的优势

Templates are evaluated at compile time, thus you can't use if() to select the appropriate conversion function at runtime (return types will conflict, hence the warnings). 模板在编译时进行评估,因此您不能使用if()在运行时选择适当的转换函数(返回类型会发生冲突,因此会出现警告)。

You need to provide type specialized implementations for your cast operator instead: 您需要为您的强制转换运算符提供类型专用实现:

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. ...

The answer by Martin Booner has already pointed out the core issue. Martin Booner的回答已经指出了核心问题。 I am going to suggest a simpler solution for what you want to accomplish in your class. 我将为您想要在课堂上完成的内容提出一个更简单的解决方案。

Using templates for classes and functions is worthwhile only when the implementation is generic. 仅当实现是通用的时,才能使用类和函数模板。 That's not true in your case. 在你的情况下,这不是真的。 The logic to return a int is different that logic to return a double . 返回int逻辑与返回double逻辑不同。 Using a member function template for this is not the best use of templates. 使用成员函数模板不是模板的最佳用途。

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);
}

is not any simpler than: 并不比任何简单:

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);
}

even though the latter is more verbose due the presence of more functions. 即使后者由于存在更多功能而更加冗长。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM