Явное приведение типов и lexical_cast

198
26 ноября 2016, 19:08

Пример кода:

#include <iostream>
#include <string>
struct A
{
    int a;
    explicit operator std::string() {
        return "<" + std::to_string(a) + ">";
    }
};
void f(std::string s) {
    std::cout << s << std::endl;
}
int main()
{
    A a {1};
    f(static_cast<std::string>(a));
    f(std::string(a));
    f((std::string)a);
    // f(boost::lexical_cast<std::string>(a));
    return 0;
}

Вопроса 2:

1) Можно ли запретить приведение типов в С-стиле, так, чтобы на вызов f(std::string(a)) или f((std::string)a) компилятор ругался, а f(static_cast<std::string>(a)) работало?

2) Как "научить" срабатывать вызов f(boost::lexical_cast<std::string>(a))?

Answer 1

Что касается запрета приведения в стиле C, могу только посоветовать посмотреть в сторону опций компилятора. В GCC, например, можно добавить флаги -Wold-style-cast и -Werror, тогда приведение в стиле C будет вызывать предупреждение, а предупреждения будут трактоваться как ошибки.

С boost::lexical_cast все просто, нужно добавить специализацию шаблона. Ваш пример примет такой вид:

#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>
struct A
{
    int a;
    explicit operator std::string() const{
        return "<" + std::to_string(a) + ">";
    }
};
namespace boost{
    template<>
    std::string lexical_cast<std::string, A>(const A& arg){
        return std::string(arg);
    }
};
void f(std::string s) {
    std::cout << s << std::endl;
}
int main()
{
    A a {1};
    f(static_cast<std::string>(a));
    f(std::string(a));
    f((std::string)a);
    f(boost::lexical_cast<std::string>(a));
    return 0;
}
Answer 2

Сообразил некое костыльное решение для запрета преобразований без static_cast:

#include <iostream>
#include <string>
template <class T, class X>
T my_cast(X&& x) {
    return static_cast<T>(x);
}
#define static_cast my_cast
struct A
{
    int a;
private:    
    explicit operator std::string() const {
        return "<" + std::to_string(a) + ">";
    }
    template <class T, class X>
    friend T my_cast(X&& x);
};
void f(std::string s) {
    std::cout << s << std::endl;
}
int main()
{
    A a {1};
    f(static_cast<std::string>(a)); // ok
    f(std::string(a)); // error
    f((std::string)a); // error
    return 0;
}
READ ALSO
Не получается получить имя файла в gtkmm (виджет FileChooserButton)

Не получается получить имя файла в gtkmm (виджет FileChooserButton)

Это мой код, когда я выбираю файл срабатывает callback, но функция get_filename возвращает пустую строку ""

224
Не выводит имя двоечника

Не выводит имя двоечника

должно вывести фамилию Shevcenko но не работает не могу разобраться

176
Сколько разделов может быть в ОС

Сколько разделов может быть в ОС

Использовал функцию GetLogicalDevices и возник вопрос, сколько может быть логических разделов в Windows? 26 - как и количество букв в английском языке...

196
Множественное наследование и VC++

Множественное наследование и VC++

В ходе дискуссии пришли к такой программе:

187