C ++ неоднозначные перегрузки шаблонов - PullRequest
0 голосов
/ 13 февраля 2019

Я пытаюсь использовать специализацию шаблонов, чтобы возвращать разные типы в зависимости от значения переменной шаблона.

Я перешел от попытки ветвиться во время выполнения, а не во время компиляции с использованием typeof(), неспециализированнаяшаблоны и использование std::enable_if_t<>.Я думаю, что это может быть связано с отсутствием понимания того, как разрешаются функции шаблона.

class Test
{
public:
    template <typename T>
    T request()
    {
        T ret = getVal<T>();
        return ret;
    }

private:
    float foo = 2.f;
    int bar = 1;

    template <typename T>
    typename std::enable_if<std::is_same<T, float>::value, bool>::type
    getVal() { return foo; }

    template <typename T>
    typename std::enable_if<std::is_same<T, int>::value, bool>::type
    getVal() { return bar; }

    template<typename T>
    T getVal()
    {
        std::cout << "T is type " << typeid(T).name() << std::endl;
        throw std::bad_typeid();
    }
};

int main()
{
    Test t;
    int i;
    float f;
    i = t.template request<int>();
    f = t.template request<float>();
}

Я ожидаю, что это разрешит три разные функции, но я не уверен, что это так:

T Test::getVal()

int Test::getVal()

float Test::getVal()

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Вы можете сделать это довольно легко, специализируя getVal(), хотя вы могли бы упростить вопрос

class Test {
public:
    template <typename T>
    T request() {
        T ret = getVal<T>();
        return ret;
    }

private:
    float foo = 2.f;
    int bar = 1;

    template<typename T>
    T getVal() {
        std::cout << "T is type " << typeid(T).name() << std::endl;
        throw std::bad_typeid();
    }
};

// add specializations
template<>
float Test::getVal<float>() { return foo; }

template <>
int Test::getVal<int>() { return bar; }

int main() {
    Test t;
    int i = t.request<int>(); // don't need template keyword here
    float f = t.request<float>();
}

Если вы можете использовать c ++ 17, с * 1005 это еще проще* и один getVal

template<typename T>
auto getVal() {
  if constexpr (std::is_same_v<int, T>) {
    return foo;
  } else if constexpr (std::is_same_v<float, T>) {
    return bar;
  } else {
    std::cout << "T is type " << typeid(T).name() << std::endl;
    throw std::bad_typeid();
  }
}
0 голосов
/ 13 февраля 2019

Ваша проблема в том, что template<typename T> T getVal() делает вызов неоднозначным, когда SFINAEd успешно завершается.

Одним из решений является ограничение этого с условием дополнения ...

Но диспетчеризация тегов - это легкоАльтернативный способ решения вашей проблемы:

template <typename> struct Tag{};

class Test
{
public:
    template <typename T>
    T request() const
    {
        return getVal(Tag<T>{});
    }

private:
    float foo = 2.f;
    int bar = 1;

    float getVal(Tag<float>) const { return foo; }
    int getVal(Tag<int>) const { return bar; }

    template<typename T> void getVal(Tag<T>) = delete;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...