C++模板功能的明确实例化导致“无定义”错误。

发布于 2025-01-29 16:01:23 字数 3126 浏览 2 评论 0原文

当试图编译文件时,发生此错误时发生:

错误

Logging.h: In instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]':
Logging.h:10:64:   required from here
Logging.h:10:64: error: explicit instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]' but no definition available [-fpermissive]
     template void printBoardWithCandidates<3>(const Board<3>& b);
                                                                ^

因为我在C ++方面不是很有经验,所以我看不出任何可能导致此问题的原因。由于该定义存在于.cpp文件中,因此我认为没有任何理由不编译。有人不介意向我解释吗?

.h文件

#pragma once
#include "Board.h"
namespace Sudoku
{
    template<int BASE>
    void printBoardWithCandidates(const Board<BASE> &b);


    template void printBoardWithCandidates<2>(const Board<2>&);
    template void printBoardWithCandidates<3>(const Board<3>&);
    template void printBoardWithCandidates<4>(const Board<4>&);
} 

.cpp文件

#include "Logging.h"
#include <iostream>

template<int BASE>
void Sudoku::printBoardWithCandidates(const Board<BASE> &board)
{
    // definition...
}

编辑: 在整个程序中,我已经使用了多次的类似实施。例如 board.h

#pragma once
#include <vector>
#include <cstring>
#include "stdint.h"

namespace Sudoku
{
    struct Cell
    {
        int RowInd;
        int ColInd;
        int BoxInd;

        friend bool operator==(const Cell& cell1, const Cell& cell2);
    };
    
    bool operator==(const Cell& cell1, const Cell& cell2);


    template<int BASE>
    class Board
    {
        public:
            static constexpr int WIDTH = BASE * BASE;
            static constexpr int CELL_COUNT = WIDTH * WIDTH;
            static constexpr uint16_t CELL_COMPLETELY_OCCUPIED = 65535 >> (sizeof(uint16_t) * 8 - WIDTH);

        private:   
            const int EMPTY_VALUE;
            
            uint16_t rowOccupants[WIDTH] = {0};
            uint16_t colOccupants[WIDTH] = {0};
            uint16_t boxOccupants[WIDTH] = {0};

            int* solution;
            void Init();
            void Eliminate(Cell& cell, uint16_t value);

        public:


            std::vector<Cell> EmptyCells;
            Board(const int* puzzle, int* solution, int emptyValue = -1);
            void SetValue(Cell cell, uint16_t value);
            void SetValue(Cell cell, int value);
            int* GetSolution() const; 
            inline uint16_t GetOccupants(Cell cell) const
            {
                return rowOccupants[cell.RowInd] | colOccupants[cell.ColInd] | boxOccupants[cell.BoxInd];
            }

    };
    template class Board<2>;
    template class Board<3>;
    template class Board<4>;
} // namespace Sudoku

When trying to compile the files bellow this error occurs:

The error

Logging.h: In instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]':
Logging.h:10:64:   required from here
Logging.h:10:64: error: explicit instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]' but no definition available [-fpermissive]
     template void printBoardWithCandidates<3>(const Board<3>& b);
                                                                ^

As I am not very experienced in C++ I don't see any possible cause for this problem. Since the definition is present in .cpp file I dont see any reason not to compile. Wouldn't someone mind explaing that to me, please?

.h file

#pragma once
#include "Board.h"
namespace Sudoku
{
    template<int BASE>
    void printBoardWithCandidates(const Board<BASE> &b);


    template void printBoardWithCandidates<2>(const Board<2>&);
    template void printBoardWithCandidates<3>(const Board<3>&);
    template void printBoardWithCandidates<4>(const Board<4>&);
} 

.cpp file

#include "Logging.h"
#include <iostream>

template<int BASE>
void Sudoku::printBoardWithCandidates(const Board<BASE> &board)
{
    // definition...
}

Edit:
Similar implementatiin I have employed several times throughout the program. For example
Board.h

#pragma once
#include <vector>
#include <cstring>
#include "stdint.h"

namespace Sudoku
{
    struct Cell
    {
        int RowInd;
        int ColInd;
        int BoxInd;

        friend bool operator==(const Cell& cell1, const Cell& cell2);
    };
    
    bool operator==(const Cell& cell1, const Cell& cell2);


    template<int BASE>
    class Board
    {
        public:
            static constexpr int WIDTH = BASE * BASE;
            static constexpr int CELL_COUNT = WIDTH * WIDTH;
            static constexpr uint16_t CELL_COMPLETELY_OCCUPIED = 65535 >> (sizeof(uint16_t) * 8 - WIDTH);

        private:   
            const int EMPTY_VALUE;
            
            uint16_t rowOccupants[WIDTH] = {0};
            uint16_t colOccupants[WIDTH] = {0};
            uint16_t boxOccupants[WIDTH] = {0};

            int* solution;
            void Init();
            void Eliminate(Cell& cell, uint16_t value);

        public:


            std::vector<Cell> EmptyCells;
            Board(const int* puzzle, int* solution, int emptyValue = -1);
            void SetValue(Cell cell, uint16_t value);
            void SetValue(Cell cell, int value);
            int* GetSolution() const; 
            inline uint16_t GetOccupants(Cell cell) const
            {
                return rowOccupants[cell.RowInd] | colOccupants[cell.ColInd] | boxOccupants[cell.BoxInd];
            }

    };
    template class Board<2>;
    template class Board<3>;
    template class Board<4>;
} // namespace Sudoku

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

羁绊已千年 2025-02-05 16:01:23

问题是,在您提供3 显式模板Instantiation 的标题文件中的点, definiti >不可用的是相应的成员函数模板printboardWithCandidates。因此,编译器无法生成这些实例化的定义,并给出了上述错误说:

error: explicit instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]' 
but no definition available [-fpermissive]
^^^^^^^^^^^^^^^^^^^^^^^^^^^

解决此问题的方法有两种,如下所示。还请注意,我使用了一个空结构,因为您提供的board类非常大(长度),如果在这里粘贴了2次,将占用很多空间。这个概念是相同的。

方法1

在提供3个显式模板实例之前,在标题中提供了成员函数模板printboardwithCandidates,如下所示:

header.h

#pragma once
#include "Board.h"
namespace Sudoku
{
    template<int BASE>
    void printBoardWithCandidates(const Board<BASE> &b)
    {
        //note this is a definition
    }

    //explicit template instantiation declaration
    extern template void printBoardWithCandidates<2>(const Board<2>&);
    extern template void printBoardWithCandidates<3>(const Board<3>&);
    extern template void printBoardWithCandidates<4>(const Board<4>&);
} 

board.h

#pragma once
template<int>
struct Board 
{
    
};

main.cpp


#include <iostream>

#include "header.h"
//explicit template instantiation definition
template void Sudoku::printBoardWithCandidates<2>(const Board<2>&);
template void Sudoku::printBoardWithCandidates<3>(const Board<3>&);
template void Sudoku::printBoardWithCandidates<4>(const Board<4>&);
int main()
{
    
    return 0;
}

工作demo


方法2

在这里我们提供了成员的定义函数模板以及源文件中的3个显式模板实例化。在标题文件中,我们仅提供成员函数模板的声明,并且标题文件中没有提供明确的模板实例化。

header.h

#pragma once
#include "Board.h"
namespace Sudoku
{
    //this is a declaration not a definition
    template<int BASE>
    void printBoardWithCandidates(const Board<BASE> &b);


   //no explicit template instantiation here since we have provided only the declaration above and not the definition
} 

board.h

#pragma once
template<int>
struct Board 
{
    
};

source.cpp

#include "header.h"

//provide the definition here
template<int BASE>
void Sudoku::printBoardWithCandidates(const Board<BASE> &board)
{
    // definition...
}
 template void Sudoku::printBoardWithCandidates<2>(const Board<2>&);
    template void Sudoku::printBoardWithCandidates<3>(const Board<3>&);
    template void Sudoku::printBoardWithCandidates<4>(const Board<4>&);

main.cpp

#include <iostream>

#include "header.h"

int main()
{
    
    return 0;
}

The problem is that at the point inside the header file where you have provided the 3 explicit template instantiation, the definition of the corresponding member function template printBoardWithCandidates is not available. Thus, the compiler cannot generate the definition for these instantiations and gives the mentioned error saying:

error: explicit instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]' 
but no definition available [-fpermissive]
^^^^^^^^^^^^^^^^^^^^^^^^^^^

There are two ways to solve this as shown below. Note also that i have used an empty struct Board since the Board class you provided is very big(in length) and will take a lot of space if pasted here 2 times. The concept is the same though.

Method 1

Provide the definition for the member function template printBoardWithCandidates in the header before providing the 3 explicit template instantiations as shown below:

header.h

#pragma once
#include "Board.h"
namespace Sudoku
{
    template<int BASE>
    void printBoardWithCandidates(const Board<BASE> &b)
    {
        //note this is a definition
    }

    //explicit template instantiation declaration
    extern template void printBoardWithCandidates<2>(const Board<2>&);
    extern template void printBoardWithCandidates<3>(const Board<3>&);
    extern template void printBoardWithCandidates<4>(const Board<4>&);
} 

Board.h

#pragma once
template<int>
struct Board 
{
    
};

main.cpp


#include <iostream>

#include "header.h"
//explicit template instantiation definition
template void Sudoku::printBoardWithCandidates<2>(const Board<2>&);
template void Sudoku::printBoardWithCandidates<3>(const Board<3>&);
template void Sudoku::printBoardWithCandidates<4>(const Board<4>&);
int main()
{
    
    return 0;
}

Working demo


Method 2

Here we provide the definition of the member function template as well as the 3 explicit template instantiations in the source file. In the header file we only provide the declaration for the member function template and no explicit template instantiation are provided in the header file.

header.h

#pragma once
#include "Board.h"
namespace Sudoku
{
    //this is a declaration not a definition
    template<int BASE>
    void printBoardWithCandidates(const Board<BASE> &b);


   //no explicit template instantiation here since we have provided only the declaration above and not the definition
} 

Board.h

#pragma once
template<int>
struct Board 
{
    
};

source.cpp

#include "header.h"

//provide the definition here
template<int BASE>
void Sudoku::printBoardWithCandidates(const Board<BASE> &board)
{
    // definition...
}
 template void Sudoku::printBoardWithCandidates<2>(const Board<2>&);
    template void Sudoku::printBoardWithCandidates<3>(const Board<3>&);
    template void Sudoku::printBoardWithCandidates<4>(const Board<4>&);

main.cpp

#include <iostream>

#include "header.h"

int main()
{
    
    return 0;
}

Working demo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文