我正在尝试使用自定义类型为 std::vector
创建显式模板实例化。
//test.hpp
#ifndef TEST_HPP_JXIGJWWK
#define TEST_HPP_JXIGJWWK
template<typename T>
struct Test {
Test(int) {}
T value;
};
#endif /* end of include guard: TEST_HPP_JXIGJWWK */
另外,我有一个带有外部实例化声明的包装器
//test_include.hpp
#ifndef TEST_INCLUDE_HPP_IBQ8DOTW
#define TEST_INCLUDE_HPP_IBQ8DOTW
#include <vector>
#include <string>
#include "test.hpp"
extern template struct Test<std::string>;
extern template class std::allocator<Test<std::string>>;
extern template class std::vector<Test<std::string>>;
#endif /* end of include guard: TEST_INCLUDE_HPP_IBQ8DOTW */
我有明确模板定义的另一个文件:
another.cpp
#include "test_include.hpp"
template struct Test<std::string>;
template class std::allocator<Test<std::string>>;
template class std::vector<Test<std::string>>;
主文件:
#include "test_include.hpp"
#include "another.hpp"
#include <iostream>
int main() {
std::vector<Test<std::string>> v;
std::cout << v.size() << std::endl;
return 0;
}
当我尝试构建它时,我看到以下错误:
In file included from /usr/include/c++/9/vector:65,
from /home/dima/extern_template_check/test_include.hpp:4,
from /home/dima/extern_template_check/another.cpp:1:
/usr/include/c++/9/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = Test<std::__cxx11::basic_string<char> >; _Args = {}]’:
/usr/include/c++/9/bits/stl_uninitialized.h:545:18: required from ‘static _ForwardIterator std::__uninitialized_default_n_1<_TrivialValueType>::__uninit_default_n(_ForwardIterator, _Size) [with _ForwardIterator = Test<std::__cxx11::basic_string<char> >*; _Size = long unsigned int; bool _TrivialValueType = false]’
/usr/include/c++/9/bits/stl_uninitialized.h:601:20: required from ‘_ForwardIterator std::__uninitialized_default_n(_ForwardIterator, _Size) [with _ForwardIterator = Test<std::__cxx11::basic_string<char> >*; _Size = long unsigned int]’
/usr/include/c++/9/bits/stl_uninitialized.h:663:44: required from ‘_ForwardIterator std::__uninitialized_default_n_a(_ForwardIterator, _Size, std::allocator<_Tp>&) [with _ForwardIterator = Test<std::__cxx11::basic_string<char> >*; _Size = long unsigned int; _Tp = Test<std::__cxx11::basic_string<char> >]’
/usr/include/c++/9/bits/stl_vector.h:1603:36: required from ‘void std::vector<_Tp, _Alloc>::_M_default_initialize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = Test<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<Test<std::__cxx11::basic_string<char> > >; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/home/dima/extern_template_check/another.cpp:5:21: required from here
/usr/include/c++/9/bits/stl_construct.h:75:7: error: no matching function for call to ‘Test<std::__cxx11::basic_string<char> >::Test()’
75 | { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/dima/extern_template_check/test_include.hpp:6,
from /home/dima/extern_template_check/another.cpp:1:
/home/dima/extern_template_check/test.hpp:6:5: note: candidate: ‘Test<T>::Test(int) [with T = std::__cxx11::basic_string<char>]’
6 | Test(int) {}
| ^~~~
/home/dima/extern_template_check/test.hpp:6:5: note: candidate expects 1 argument, 0 provided
/home/dima/extern_template_check/test.hpp:5:8: note: candidate: ‘Test<std::__cxx11::basic_string<char> >::Test(const Test<std::__cxx11::basic_string<char> >&)’
5 | struct Test {
| ^~~~
/home/dima/extern_template_check/test.hpp:5:8: note: candidate expects 1 argument, 0 provided
/home/dima/extern_template_check/test.hpp:5:8: note: candidate: ‘Test<std::__cxx11::basic_string<char> >::Test(Test<std::__cxx11::basic_string<char> >&&)’
/home/dima/extern_template_check/test.hpp:5:8: note: candidate expects 1 argument, 0 provided
令人惊讶的是,如果 Test
类有一个默认的构造函数,代码就能成功编译。
我应该添加或更改什么才能使其正常工作?
编译器版本:clang 11。
最佳答案
根据标准,当您显式实例化模板时,类的所有非模板化成员都会被实例化(相对于根据 [temp.inst] 来自隐式实例化的按需实例化)。
[temp.explicit]*
An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its direct non-template members that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, provided that the associated constraints, if any, of that member are satisfied by the template arguments of the explicit instantiation
问题是 vector
有非模板成员,如 resize
需要 T
是默认可构造的。 MSVC 编译器在其错误消息中使这一点更加明显:
vector(1191): note: while compiling class template member function 'void std::vector<Test<std::string>,std::allocator<Test<std::string>>>::resize(const unsigned __int64)'
修复
标准语*中的关键词是
[...] provided that the associated constraints, if any, of that member are satisfied by the template arguments of the explicit instantiation
问题似乎是 vector
的实现还没有 catch C++20;像resize
这样的功能不受例如 requires DefaultConstructible<T>
的限制.查看 libstdc++ 的源代码 vector证实了这一点。
实际的解决方案可能是“等待”。
与此同时,如果您可以为您的类提供默认构造函数,那就去做吧。否则,您不能使用显式模板实例化。
* 关于约束的措辞在 C++20 之前不存在,因此如果您希望最终修复此问题,您还需要升级您的 C++ 版本
关于c++ - 如何为具有自定义类型的 std::vector 创建显式模板实例化声明?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69556553/