繁体   English   中英

显式构造函数仍在进行转换

[英]explicit constructor still doing conversions

我有一个(非常)简单的模板化类型,它允许我从函数返回时返回“IsValid”标志。 它如下:

template <typename T>
struct Validated
{
private:
    T m_value;
    bool m_isValid;

public:
    Validated() : m_value(), m_isValid(false) {}
    explicit Validated(T const& value) : m_value(value), m_isValid(true) {}
    explicit Validated(bool isValid, T const& value) : m_value(value), m_isValid(isValid) {}
    explicit Validated(bool isValid, T&& value) : m_value(value), m_isValid(isValid) {}    

    bool IsValid() const { return m_isValid; }
    T const& Value() const { return m_value; }
};

也许有一些我不明白的explicit说明符,但我想知道为什么以下工作正常,我怎么能避免从bool转换为double?

void someFunc()
    {
    Validated<double> foo(1.0); // this makes perfect sense
    Validated<double> bar(true); // works... (sets m_value to 1.0)
    }

一直在看类似的问题/答案,但找不到任何令人满意的问题。 我知道std::optional存在,但我们还没有进入c ++ 17。 在VS2012 / v110上试过这个。

更新:根据建议,删除bool的构造函数可以完成工作(从c ++ 14开始)。 它不适用于c ++ 11(VS2012 / toolset v110)。

你可以简单地删除一个bool的构造函数:

Validated(bool value) = delete;

注意:如果您希望Validated<bool>是有效类型,则可能需要一些额外的预防措施。


您还可以防止除T之外的任何类型的构造(比前一个更强):

template <class U>
Validated(U) = delete;

这甚至可以使用Validated<bool>因为T构造将匹配您的Validated(T const&)重载,而来自T以外的任何类型的构造将匹配已删除的模板。

此方法将防止(甚至明确)建设Validated<double>11f ,等等,所以你可能不希望使用它。


explicit不会使您的代码格式错误,它会阻止从T隐式构造Validated<T> ,例如:

void f(Validated<double>);

f(1.0); // ill-formed because the conversion would be implicit

你可以在所有情况下禁用Validated(bool)构造函数,除了T = bool之类的东西...

#include <iostream>
#include <type_traits>

using namespace std;
template <typename T>
struct Validated
{
private:
    T m_value;
    bool m_isValid;

public:
    Validated() : m_value(), m_isValid(false) {}


    explicit Validated(T const& value) : m_value(value), m_isValid(true) {}

    template <typename Y=T,typename std::enable_if<!std::is_same<Y,bool>::value,int>::type =0>
    explicit Validated(bool const& value) = delete;

    explicit Validated(bool isValid, T const& value) : m_value(value), m_isValid(isValid) {}
    explicit Validated(bool isValid, T&& value) : m_value(value), m_isValid(isValid) {}    

    bool IsValid() const { return m_isValid; }
    T const& Value() const { return m_value; }
};

int main() {
    Validated<bool> v(true);
    //Validated<int> v2(true); //fails
    Validated<int> v2(2);
    return 0;
}

演示

这里的问题是传递给构造函数的参数可以隐式转换为构造函数参数类型。 为了防止这种情况,您可以将构造函数转换为模板,并检查参数类型是否与模板参数完全匹配:

template<typename TT> explicit
Validated(TT const& value) : m_value{value}, m_isValid{true}
{
   static_assert
   (
       ::std::is_same_v<TT, T>
   ,   "constructor argument type should match template parameter"
   );
}

在线编译器

暂无
暂无

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

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