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

时间:2018-06-26 16:00:11

标签: c++

我有一个(非常)简单的模板化类型,当我从函数中返回时,可以让我返回“ 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修饰符有些我不理解的东西,但是我想知道为什么下面的方法工作得很好,如何避免从布尔转换为双精度?

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)。

3 个答案:

答案 0 :(得分:4)

您只需删除一个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不会使您的代码格式错误,它可以防止从Validated<T>隐式构造T,例如:

void f(Validated<double>);

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

答案 1 :(得分:0)

除了T = bool时,在所有情况下都可以禁用Validated(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;
}

Demo

答案 2 :(得分: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"
   );
}

online compiler