簡體   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