Метапрограммирование шаблона: проблемы с частичной специализацией - PullRequest
2 голосов
/ 07 августа 2020

Я пытаюсь изучить частичную специализацию шаблонов, чтобы построить систему черт. К сожалению, я не могу заставить работать полную версию. Я создал простейшую модель, чтобы показать, что не работает. Мне даже не ясно, пробую ли я что-то, что не поддерживается (на самом деле я вижу несколько примеров того же характера, но дьявол кроется в деталях).

Я просто создаю небольшой пример, в котором У меня есть два перечисления, и я хотел бы создать строку по-разному в зависимости от их комбинации. Конечно, это всего лишь фиктивный пример, показывающий проблему, то же самое в этом случае можно сделать многими другими способами.

#ifndef TESTTRAITS_H_
#define TESTTRAITS_H_

#include <string>

using namespace std;

enum MovementType {
    WALKS = 0, SWIMS = 1
};

enum AnimalType {
    DOG = 0, CAT = 1, DOLPHIN = 2
};

template<AnimalType A, MovementType B>
struct movementAnimal {
    static const string quality;
};

template<AnimalType A>
struct movementAnimal<A,WALKS> {
    static const string quality;
};

template<AnimalType A>
struct movementAnimal<A,SWIMS> {
    static const string quality;
};

#endif /* TESTTRAITS_H_ */

Теперь я пишу присвоение переменной stati c

#include "TestTraits.h"

template<>
const string movementAnimal<DOLPHIN, WALKS>::quality = "Not capable";

template<>
const string movementAnimal<DOLPHIN, SWIMS>::quality = "Excellent";

template<AnimalType A>
const string movementAnimal<A, SWIMS>::quality = "Decent";

template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";

И небольшая основная функция

#include <iostream>
using namespace std;
#include "TestTraits.h"

int main() {
    cout << movementAnimal<DOLPHIN,WALKS>::quality  << endl;
    cout << movementAnimal<DOG,WALKS>::quality  << endl;
    return 0;
}

Если я компилирую, то получаю ошибку:

/ src / TestProject. cpp: 15: undefined ссылка на `motionAnimal <(AnimalType) 0, (MovementType) 0> :: quality [abi: cxx11] 'collect2: error: ld вернула 1 статус выхода>

Если я удалю ссылку на motionAnimal :: quality, тогда он компилируется отлично.

Я понимаю, что он не переваривает частичную спецификацию шаблона

template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";

Я не знаю, почему и возможно ли, чтобы этот шаблон работал.

1 Ответ

4 голосов
/ 07 августа 2020

Как я вижу, вы помещаете эти определения в отдельные файлы. Определение классов шаблона находится в TestTraits.h, но определение stati c consts находится в другом месте. Основной файл CPP включает только TestTraits.h. Это должно звучать как хорошее решение, но это не работает в мире шаблонов.

Итак, вы определили перечисления и шаблоны / частичные специализации. Ваш основной модуль cpp видит эти определения. Хорошо. Компилятору известны классы шаблонов, когда он создает здесь экземпляр прогулочной собаки:

cout << movementAnimal<DOG,WALKS>::quality  << endl;

Видит ли компилятор определение stati c const? В противном случае такой код бесполезен:

template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";

Когда компилятор видит приведенный выше код, он не может знать все значения A, которые вы бы использовали. Поэтому всякий раз, когда вы решаете, что DOG WALKS, эта точка создания экземпляра должна видеть определение const string movementAnimal<A, WALKS>::quality;

. Решение состоит в том, чтобы убедиться, что код из основной функции знает как определения классов шаблонов, так и определения stati c consts.

Есть два решения. Во-первых, поместить все в один файл заголовка или включить оба файла из файла cpp. Не забудьте включить оба.

Второе решение - иметь явное создание экземпляров некоторых классов где-нибудь в вашем коде:

template class movementAnimal<DOG, WALKS>;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...