如何防止构造函数中的 bool 到 int 转换?

rui*_*eco 5 c++ c++17

我有以下课程,尽可能接近我的生产代码:

#include <iostream>

template <typename T>
struct M {

    M(std::string a, std::string b, T value = T(), const bool ready = false) : m_value{value}, m_ready{ ready } {}

    T m_value;
    bool m_ready;

};

auto main() -> int {
    {
        M<int> m{"a", "b"};
        std::cerr << m.m_value << std::endl;
    }
    {
        M<int> m{"a", "b", true};
        std::cerr << m.m_value << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,m_value正如预期的那样, 的值为 0。在第二个中它是 1,因为它采用 bool 的值。有没有办法避免转换?

Nic*_*las 5

您可以通过显式删除直接bool作为第三个参数的版本来阻止转换:

M(std::string, std::string, bool, bool = false) = delete;
Run Code Online (Sandbox Code Playgroud)

但是,如果Tbool,那将导致问题。因此,您需要使用一些 SFINAE 体操来使此定义仅在T可转换为bool实际上 不是bool.


Bar*_*rry 4

您可以添加另一个构造函数来拒绝任何不完全正确的内容T

template <typename T>
struct M {
    M(std::string a, std::string b, T value = T(), const bool ready = false);

    template <typename U>
    M(std::string, std::string, U, bool = false) = delete;
};
Run Code Online (Sandbox Code Playgroud)

M<int>("hello", hello", true)会更喜欢构造函数模板,该模板已被删除。但请注意,也会M<int>("hello", "hello", '4')如此M<int>("hello", "hello", 4u)。因此,问题是要真正解决您要删除哪些具体内容。

如果您实际上只想准确拒绝bool,则可以通过约束模板来做到这一点:

template <typename U, std::enable_if_t<std::is_same_v<U, bool>, int> = 0>
M(std::string, std::string, U, bool = false) = delete;
Run Code Online (Sandbox Code Playgroud)

或者,在 C++20 中:

template <std::same_as<bool> U>
M(std::string, std::string, U, bool = false) = delete;
Run Code Online (Sandbox Code Playgroud)

或者:

M(std::string, std::string, std::same_as<bool> auto, bool = false) = delete;
Run Code Online (Sandbox Code Playgroud)

这样做仍然允许从两个s 和 aM<bool>进行构造,因为非模板构造函数仍然是更好的匹配。stringbool