специализировать шаблонную функцию c ++, когда два типа совпадают - PullRequest
0 голосов
/ 01 апреля 2019

Мой пример использования следующий. Для данного объекта мне нужны читабельные средства определения, является ли этот объект подклассом другого объекта. Очевидно, что в основе лежит вызов dynamic_cast, но я хочу что-то более читабельное. Итак, у меня есть следующее:

template <typename C, typename T>
bool isInstanceOf(const T& t) noexcept {
    if (typeid(t) == typeid(C)) {
        return true;
    }
    if (dynamic_cast<const C*>(&t) != nullptr) {
        return true;
    }
    return false;
}

Это работает, как задумано, но если я сделаю вызов, когда C и T на самом деле одного типа, я получу предупреждение компилятора на dynamic_cast, потому что компилятор знает, что он никогда не вернет ноль. Это подводит меня к моему вопросу: могу ли я написать специализированную версию этого, которая просто возвращает true, если C и T на самом деле одного типа.

Я попробовал очевидное

template <typename C>
inline bool isInstanceOf(const C& t) noexcept {
    return true;
}

но это дает мне ошибку: «Вызов isInstanceOf 'неоднозначен».

Это на самом деле не высокоприоритетный элемент, так как я бы никогда не назвал isInstanceOf<B>(b), где я знаю, что b относится к типу B, но он есть в моих модульных тестах на полноту и я хотел бы увидеть, есть ли способ заставить компилятор оптимизировать его без предупреждения.

Если это поможет, вот предупреждение, которое я получаю:

In file included from Tests/rtti.cpp:15:0:
.build/Linux-x86_64/include/kss/util/rtti.hpp: In instantiation of ‘bool kss::util::rtti::isInstanceOf(const T&) [with C = {anonymous}::B; T = {anonymous}::B]’:
Tests/rtti.cpp:81:9:   required from here
.build/Linux-x86_64/include/kss/util/rtti.hpp:61:40: warning: the compiler can assume that the address of ‘t’ will never be NULL [-Waddress]
     if (dynamic_cast<const C*>(&t) != nullptr) {
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~

Ответы [ 2 ]

1 голос
/ 01 апреля 2019

Если у вас есть C ++ 17, вы можете использовать if constexpr:

template <typename C, typename T>
bool isInstanceOf(const T& t) noexcept {
    if constexpr (std::is_same<T, C>::value) {
        return true;
    } else {
        return dynamic_cast<const C*>(&t) != nullptr;
    }
}

До C ++ 17, перегрузки и SFINAE (или диспетчеризация тегов) могут выполнять эту работу:

template <typename C>
bool isInstanceOf(const C& t) noexcept {
    return true;
}

template <typename C, typename T>
std::enable_if_t<!std::is_same<C, T>::value, bool>
isInstanceOf(const T& t) noexcept {
    return dynamic_cast<const C*>(&t) != nullptr;
}
0 голосов
/ 01 апреля 2019

Не совсем то, что вы просили, и в основном для развлечения, но ... как насчет пары перегруженных шаблонами функций, как указано ниже

template <typename T>
bool isIstanceOf (T const &) noexcept
 { return true; }

template <typename>
bool isIstanceOf (...) noexcept
 { return false; }

что вам нужно позвонить с объяснением типа T?

Но более "is-преобразуемо в", чем "is-instance-of".

Ниже приводится полный пример компиляции

#include <iostream>

template <typename T>
bool isIstanceOf (T const &) noexcept
 { return true; }

template <typename>
bool isIstanceOf (...) noexcept
 { return false; }

struct A
 { };

struct B : public A
 { };

int main()
 {
   A  a;
   B  b;

   std::cout << isIstanceOf<A>(a) << std::endl;    // print 1
   std::cout << isIstanceOf<A>(b) << std::endl;    // print 1
   std::cout << isIstanceOf<B>(a) << std::endl;    // print 0
   std::cout << isIstanceOf<B>(b) << std::endl;    // print 1
   std::cout << isIstanceOf<int>(a) << std::endl;  // print 0
   std::cout << isIstanceOf<int>(b) << std::endl;  // print 0
 }
...