Проблема заключается в заданном пользователем шаблоне функции неявного преобразования.
template<typename T>
operator T()
{
return data;
}
Когда компилятор учитывает выражение data["TestNode"]
, необходимо выполнить некоторые неявные преобразования. Компилятор имеет две опции:
- Преобразование
const char [9]
в const std::string
и вызов Setting &Setting::operator[](const std::string)
- Преобразование
Setting
в int
и вызов const char *operator[](int, const char *)
Обе опции включают неявное преобразование, поэтому компилятор не может решить, какой из них лучше. Компилятор говорит, что вызов неоднозначен.
Есть несколько способов обойти это.
Опция 1
Устранить неявное преобразование из const char [9]
в std::string
. Вы можете сделать это, сделав Setting::operator[]
шаблоном, который принимает ссылку на массив символов (ссылку на строковый литерал).
template <size_t Size>
Setting &operator[](const char (&key)[Size]);
Опция 2
Устраните неявное преобразование от Setting
до int
. Это можно сделать, пометив пользовательское преобразование как explicit
.
template <typename T>
explicit operator T() const;
. Для этого потребуется обновить код вызова, чтобы использовать прямую инициализацию вместо инициализации копирования.
int x{data["TestNode"]};
Опция 3
Устранить неявное преобразование из Setting
в int
. Другой способ сделать это - полностью удалить пользовательское преобразование и использовать функцию.
template <typename T>
T get() const;
Очевидно, что для этого также потребуется обновить код вызова.
int x = data["TestNode"].get<int>();
Некоторые другие замечания
В коде я заметил, что вы не пометили пользовательское преобразование как const
. Если функция-член не изменяет объект, вы должны пометить его как const
, чтобы иметь возможность использовать эту функцию для постоянного объекта. Итак, поставьте const
после списка параметров:
template<typename T>
operator T() const {
return data;
}
Еще одна вещь, которую я заметил, это:
std::shared_ptr<Setting>(new Setting())
Здесь вы упоминаете Setting
дважды и делаете два выделения памяти, когда Вы могли бы сделать один. Для чистоты и производительности кода предпочтительнее сделать это:
std::make_shared<Setting>()
Еще одна вещь, я не знаю достаточно о вашем дизайне, чтобы принять это решение самостоятельно, но вам действительно нужно использовать std::shared_ptr
? Я не помню, чтобы в последний раз я использовал std::shared_ptr
, так как std::unique_ptr
был гораздо более эффективным и, кажется, этого достаточно в большинстве ситуаций. И действительно, вам вообще нужен указатель? Есть ли причина для использования std::shared_ptr<Setting>
или std::unique_ptr<Setting>
вместо Setting
? Просто о чем подумать.