Обходной путь c ++: `неверная инициализация ссылки типа 'C * &' из выражения типа B * - PullRequest
0 голосов
/ 13 июня 2018

В последнее время я впервые обнаружил эту ошибку: invalid initialization of reference of type ‘C*&’ from expression of type ‘B*’.Ошибка возникла при переносе кода с gcc 4.9 на gcc 6.Ниже я вставил минимальный пример кода.

class A {
public:
    A() : a(1) {};
    virtual ~A() {};
    int a;
};

class B : public A {
public:
    B() : val(2) {};
    int val;
};

class C : public A {
public:
    C() : val(3) {};
    float val;
};

int alloc_b(B*& entry) {
    try {
        entry = new B;
    } catch(...) {
        return -1;
    }
    return 0;
}

int alloc_c(C*& entry) {
    try {
        entry = new C;
    } catch(...) {
        return -1;
    }
    return 0;
}

template<typename T>
int whatever(const bool isB) {
    T* entry = NULL;
    if(isB) {
        alloc_b(entry);
    } else {
        alloc_c(entry);
    }

    std::cout << entry->val << "\n";
}

int main() {
    int rv;
    B* ptrB;
    C* ptrC;

    whatever<B>(true);
    whatever<C>(false);
    return 0;
}

Я понимаю, что ошибка появляется, потому что при компиляции метода whatever с isB = true он также пытается скомпилировать также вызов alloc_c(),поэтому он проверяет, что T = B и не может найти какой-либо метод alloc_c(B*& entry), поэтому он не работаетИ другой способ invalid initialization of reference of type ‘B*&’ from expression of type ‘C*’, когда метод whatever вызывается с типами C и isB = false.

Мне было просто интересно, какой самый чистый способ обойти эту проблему.Единственное решение, которое я нашел, - это создание шаблона метода alloc с некоторыми специализациями:

template<typename T>
int alloc(T*& entry) {
    static_assert((std::is_same<decltype(entry), B>::value ||
                    std::is_same<decltype(entry), C>::value),
                    "Class must be A or B");
}

template<>
int alloc(B*& entry) {
    return alloc_b(entry);
}

template<>
int alloc(C*& entry) {
    return alloc_c(entry);
}

А затем внутри функции whatever я бы вызвал это alloc вместо других allocs.

template<typename T>
int whatever(const bool isB) {
    T* entry = NULL;
    alloc(entry);

    std::cout << entry->val << "\n";
}

Но я уверен, что должен быть более чистый способ обойти эту ошибку.

1 Ответ

0 голосов
/ 13 июня 2018

Я понимаю, что ошибка появляется , потому что при компиляции метода с помощью isB = true он также пытается скомпилировать также вызов alloc_c () , поэтому он проверяет, что T = B, и можетНе удается найти метод alloc_c (B * & entry), поэтому он не работает.

Вы можете предотвратить это, указав вместо этого время компиляции isB:

template<typename T, bool isB>
int whatever();

Теперь, используя if constexpr, вы получите нужную функцию, не повредив при этом свой код:

template<typename T, bool isB>
int whatever() {
    T* entry = NULL;
    if constexpr (isB) {
        alloc_b(entry);
    } else {
        alloc_c(entry);
    }

    std::cout << entry->val << "\n";
}

whatever<B, true>();
whatever<C, false>();

Live Demo

РЕДАКТИРОВАТЬ

Без if constexpr SFINAE по-прежнему работает - вам просто нужно больше набирать:

template<typename T, bool isB>
typename std::enable_if<isB, int>::type whatever() {
    T* entry = NULL;
    alloc_b(entry);

    std::cout << entry->val << "\n";
}

template<typename T, bool isB>
typename std::enable_if<!isB, int>::type whatever() {
    T* entry = NULL;
    alloc_c(entry);

    std::cout << entry->val << "\n";
}

Протестировано с gcc 6.1.0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...