我有以下课程,尽可能接近我的生产代码:
#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 的值。有没有办法避免转换?
您可以通过显式删除直接bool作为第三个参数的版本来阻止转换:
M(std::string, std::string, bool, bool = false) = delete;
Run Code Online (Sandbox Code Playgroud)
但是,如果T是bool,那将导致问题。因此,您需要使用一些 SFINAE 体操来使此定义仅在T可转换为bool但实际上 不是bool.
您可以添加另一个构造函数来拒绝任何不完全正确的内容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