неопределенная ссылка на `operator << (std :: ostream &, / * класс с нетиповыми параметрами шаблона * / &) ' - PullRequest
0 голосов
/ 16 апреля 2020

Для домашнего задания мне нужно создать класс с нетиповыми параметрами шаблона, а затем добавить к нему std:: (i / o) stream операторов. Однако, когда я пытаюсь скомпилировать, clang ++ выдает ошибку компоновщика:

$ clang++ -o foo ./*.cpp -std=c++11 -Wall -Wextra -Wpedantic -Wconversion -Wnon-virtual-dtor
/tmp/16_15-8cda65.o: In function `main':
main.cpp:(.text+0x108): undefined reference to `operator<<(std::ostream&, Screen<9ul, 9ul> const&)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Я осознаю, что объявления и определения шаблонов должны быть в одной и той же единице перевода, и здесь есть множество вопросов и ответов, которые указывают, что out.

Мой сокращенный код выглядит следующим образом:

main. cpp:

#include <iostream>

#include "Screen.h"

int main()
{
    Screen<9,9> smile =
    {
        {0,0,0,1,1,1,0,0,0},
        {0,1,1,0,0,0,1,1,0},
        {0,1,0,0,0,0,0,1,0},
        {1,0,0,1,0,1,0,0,1},
        {1,0,0,0,0,0,0,0,1},
        {1,0,1,0,0,0,1,0,1},
        {0,1,0,1,1,1,0,1,0},
        {0,1,1,0,0,0,1,1,0},
        {0,0,0,1,1,1,0,0,0}
    };

    std::cout << smile;

    return 0;
}

Screen.h:

#ifndef SCREEN_H
#define SCREEN_H

#include <iostream>
#include <array>
#include <initializer_list>
#include <cstddef>

template <std::size_t W, std::size_t H>
class Screen
{
    /////////////
    // FRIENDS //
    /////////////

    friend std::ostream& operator<<(std::ostream&, const Screen<W,H>&);

    public:

        // declarations of ctors, public members, etc.

    private:

        //////////
        // DATA //
        //////////

        std::array<std::array<bool,W>,H> pixels;
};

/////////////////
// NON-MEMBERS //
/////////////////

// ostream operator
template <std::size_t W, std::size_t H>
std::ostream& operator<<(std::ostream&, const Screen<W,H>&);

#include "Screen_impl.h"
#endif

Screen_impl .h:

#ifndef SCREEN_IMPL_H
#define SCREEN_IMPL_H

#include <iostream>
#include <array>
#include <algorithm>
#include <stdexcept>
#include <initializer_list>
#include <cstddef>

// definitions...

/////////////////
// NON-MEMBERS //
/////////////////

// ostream operator
template <std::size_t W, std::size_t H>
std::ostream& operator<<(std::ostream& lhs, const Screen<W,H>& rhs)
{
    for (auto y = rhs.pixels.cbegin(); y < rhs.pixels.cend(); ++y)
    {
        for (auto x = y->cbegin(); x < y->cend(); ++x)
        {
            if (*x)
                lhs << '#';
            else
                lhs << ' ';
        }

        lhs << std::endl;
    }

    return lhs;
}

#endif

Ответы [ 2 ]

2 голосов
/ 16 апреля 2020

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

Вам необходимо объявить шаблон функции внутри класса как

template <std::size_t WX, std::size_t HX>
friend std::ostream& operator<<(std::ostream&, const Screen<WX, HX>&);

Обратите внимание, что параметры шаблона должны называться по-разному. из параметров шаблона класса, чтобы избежать затенения.

Вы также можете просто определить operator<< внутри класса.

1 голос
/ 16 апреля 2020

Этот оператор друга

template <std::size_t W, std::size_t H>
class Screen
{
    /////////////
    // FRIENDS //
    /////////////

    friend std::ostream& operator<<(std::ostream&, const Screen<W,H>&);
    //

не является оператором шаблона.

Поэтому его определение как оператора шаблона недопустимо. То есть это не определение оператора не шаблонного друга, объявленного в определении класса.

В результате компилятор выдает ошибку, что определение оператора не найдено.

Поместите определение оператора друга в определение класса. В этом случае это определение будет использоваться для каждой специализации класса.

В противном случае вам потребуется определить оператор для каждой конкретной специализации класса в отдельности.

Вот демонстрационная программа.

#include <iostream>
#include <iterator>
#include <numeric>

template <size_t N>
class Array
{
private:
    int a[N];

public:
    Array() 
    {
        std::iota( std::begin( a ), std::end( a ), 0 );
    }

    friend std::ostream & operator <<( std::ostream &os, const Array &a )
    {
        for ( const auto &item : a.a ) os <<item << ' ';
        return os;
    }
};

int main() 
{
    std::cout << Array<1>() << '\n';
    std::cout << Array<2>() << '\n';
    std::cout << Array<3>() << '\n';
    std::cout << Array<4>() << '\n';
    std::cout << Array<5>() << '\n';

    return 0;
}

Его вывод

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