Обновление
Если кто-то заинтересован в процессе, Проект GitHub здесь .Хотя он работает довольно хорошо, я уменьшил его до арифметических типов.
Будущие разработки принесут больше.
Спасибо всем
Оригинальный пост
Да, я знаю о этот вопрос .пожалуйста, прочитайте это для хорошего введения.И одно умное, но не универсальное решение.
Я забочусь об этом, но мне также нужно иметь в качестве неконвертируемых некоторые фундаментальные типы.Наличие этого сильно ограничит возможность появления ошибок.Не только вызовы функций без неявного преобразования, но также и для создания переменных, назначений, сравнений и т. Д.
Я уверен, что это было предпринято и, возможно, решено ранее.У меня не должно быть этого в моей программе:
// implicit conversions
// no warnings
{
char character = 127 ;
bool truth = 0 ;
size_t size_ = truth ;
int integer = false ;
size_ = integer;
size_ = character ;
}
В моем VS 2017 (в актуальном состоянии) он компилируется без предупреждений в настройках по умолчанию, даже на Level 4
aka /W4
.То же самое и с clang 7 и т. Д.
Пока мне удалось разработать это:
namespace dbj {
namespace util {
using namespace std;
template<typename T>
struct nothing_but final
{
static_assert(false == std::is_array_v<T>,
"can not deal with arrays");
using type = nothing_but;
// default creation
nothing_but() : val_(T{}) {}
// allowed conversion
nothing_but(T const & t_) : val_(t_) {}
// allowed assignment
type & operator = (T const & new_val_)
{
val_ = new_val_;
return *this;
}
/*
explictly ban all attempts to construct from
any other type but T
*/
template<
typename X,
std::enable_if_t<
false == std::is_same_v<T, X>
, int> = 0
>
nothing_but(X const & x_) = delete;
/*
explictly ban all attempts to assign from
any other type but T
*/
template<
typename X,
std::enable_if_t<
false == std::is_same_v<T, X>
, int> = 0
>
type & operator = (X const & new_val_) = delete;
/* conversion to X is banned */
template<
typename X,
std::enable_if_t<
false == std::is_same_v<T, X>
, int> = 0
>
operator X & () = delete;
// conversion to T is allowed, but const stays const
operator T & () { return val_; }
// non const value, as other std class types do
T & data() const { return (T&)val_; }
private:
T val_{};
// compatibility
friend bool operator < ( type const & left_, type const & right_)
{
return left_.val_ < right_.val_;
}
};
} // util
} // dbj
Некоторое быстрое тестирование:
{
using dbj::util::nothing_but;
nothing_but<int> si1 = 42;
si1 = 42;
nothing_but<int> si2 = 13;
//nothing_but<int> si3 = true ;
//si3 = true;
//nothing_but<int> si4 = '$' ;
//si4 = '$';
//nothing_but<int> si5 = 2.7 ;
//si5 = 2.7;
//nothing_but<int> si6 = size_t(BUFSIZ) ;
//si6 = size_t(BUFSIZ);
si1 = si2; (void)(si1 == si2);
int j = 9;
nothing_but<int *> sip1 = &j;
nothing_but<char const *> scc1 = "OK";
char name[] = "c++";
// scc1 = name;
}
И некоторое тестирование на константность
{ // constnes
const int cc = 42;
const int cb = cc;
nothing_but<int> const & sci1 = cc;
nothing_but<int> const sci2 = sci1 ; // ok
const nothing_but<int> sci3 = sci1 ; // ok
wprintf(L"%d", sci1.data()); // ok
//sci2 = sci1;
//const int ii1 = sci1;
//const int ii2 = static_cast<int>(sci1);
//const int * ii3 = const_cast<int *>(&(sci1));
const int & ii3 = (const int &)(sci1); // ok
int & ii4 = (int &)(sci1); // ok
}
{ // compatibility
// std::vector<nothing_but<bool>> bv{ true, 1 , true };
std::vector<nothing_but<bool>> bv{ true, true , true };
nothing_but<bool> bb = bv[1] ;
bool kb = bb; // OK
//int k = bb;
//int j = bv[1];
std::map< nothing_but<bool>, nothing_but<int> > bm;
bm[true] = 1;
// bm[true] = 2.3;
bm[false] = 0;
// bm[false] = 0.9;
}
и так далее.Все, что закомментировано, не компилируется.
Пока что я вижу потенциал, но я не уверен, правильно ли я это делаю?Вы когда-нибудь думали об этом как о полезном, и если бы вы сделали, вы бы сделали это по-другому?
Пожалуйста, обратите внимание, мне нужно универсальное решение, которое я называю "неконвертируемыми базовыми типами".Я надеюсь, что это может быть сделано, и это может быть довольно маленьким и общим, когда это будет сделано.