当我遇到以下答案:
通过“显式模板实例化”假设您的意思是
模板类foo< int>; //显式类型的实例化
// 或者
模板void foo< int>(); //显式功能实例化
然后这些必须在源文件中,因为它们考虑了定义,因此受到 odr 。
我的问题是,那就是上述说明不能将明确的模板实例化定义定义在技术上是正确的(必须放入源文件中)。我正在寻找来自标准(或同等源)的确切参考,其中可以指定这些ETI定义不能放入标头文件中。
我还在示例程序中尝试了此程序,该程序可以很好地编译和链接,而无需在GCC和Clang中给出任何多重定义错误(DEMO),即使我将ETIS放入标题中。 程序是否根据标准
以下给定的
#ifndef MYHEADER_H
#define MYHEADER_H
#include <string>
template<class T>
int func( const T& str)
{
return 4;
}
template int func<std::string>( const std::string& str); //first ETI in header. Will the program be well formed if this header is included in multiple source files?
template int func<double>(const double& d); //second ETI in header
#endif
#include "Header.h"
?
#include "Header.h"
main.cpp
#include <iostream>
#include "Header.h"
int main(){
std::string input = "123";
auto result = func(input);
std::cout<<result<<std::endl;
}
demo
I was reading about explicit template instantiation when i came across the following answer:
Assuming by "explicit template instantiation" you mean something like
template class Foo<int>; // explicit type instantiation
// or
template void Foo<int>(); // explicit function instantiation
then these must go in source files as they considered definitions and are consequently subject to the ODR.
My question is that is the above claim that explicit template instantiation definition cannot be put into header files(and must be put into source files) technically correct. I am looking for an exact reference from the standard(or equivalent source) where it is specified that these ETI definitions cannot be put into header files.
I also tried this in a sample program which compiles and links fine without giving any multiple definition error(demo) in both gcc and clang even though i have put the ETIs into the header. Is the below given program well-formed according to the standard?
Header.h
#ifndef MYHEADER_H
#define MYHEADER_H
#include <string>
template<class T>
int func( const T& str)
{
return 4;
}
template int func<std::string>( const std::string& str); //first ETI in header. Will the program be well formed if this header is included in multiple source files?
template int func<double>(const double& d); //second ETI in header
#endif
source2.cpp
#include "Header.h"
source3.cpp
#include "Header.h"
main.cpp
#include <iostream>
#include "Header.h"
int main(){
std::string input = "123";
auto result = func(input);
std::cout<<result<<std::endl;
}
Demo
发布评论
评论(3)
该陈述是不正确的,即使在一般假设下,可以允许将标头包含在几个翻译单元中。
而 [temp.spec.general]/5 很明显, a 显式实例化定义,含义 a 特定专业化,只能出现一次
这并不能阻止明确的实例化放置在标头中,即使在总体假设下,标头可能包含在几个翻译单元中。不,我们只需要确保,对于每个这样的翻译单元,显式实例定义实例化不同的专门。如何?使用标题文件中未命名的名称空间的反图案。
我们为什么要这样做?
该特定技术可用于通过利用
从C ++ 20开始,我们将利用该黑客的专业知识,但是Pre-C ++ 20我们将使用显式实例定义,因此:
因此,对于某些类型
foo
定义如下:我们可以规避
foo
的访问规则,如下所示:我们可以在特定的源文件中使用以下内容:
有关详细信息,请参见eg
This statement is not correct, even under the general assumption that the header may be allowed to be included in several translation units.
Whilst [temp.spec.general]/5 is clear that a explicit instantiation definition, meaning for a specific specialization, must only appear once in a program
This does not bar explicit instantiation from being placed in header, even under the general assumption that the header may be included in several translation units. No, we simply need to assure that for each such translation unit, the explicit instantiation definition instantiates different specializations. How? Using the otherwise anti-pattern of unnamed namespaces in header files.
Why would we ever want to do this?
This particular technique can be used to circumvent private access rules by leveraging [temp.spec.general]/6
As of C++20 we would leverage specializations for this hack, but pre-C++20 we'd use explicit instantiation definitions, as it allows:
Thus, for some type
Foo
defined as follows:we may circumvent the access rules of
Foo
as follows:which we may use in a particular source file as follows:
For details, see e.g.
在技术上,可以在标题中具有明确的实例化是可以的 - 只要该标头仅包含一次即可。
更准确地说它只能出现每个程序一次(这就是为什么标准确实可以做到这一点)。
实际上这几乎是一个区别,没有差异,因为首先写下这样的标题并不多。
Technically, it's fine to have an explicit instantiation in a header - so long as that header is only included once.
It's more accurate to say it can only occur once per program (which is why the standard does exactly that).
Practically this is almost a distinction without a difference, as there's not much point writing such a header in the first place.
来自显式实例化文档:
(强调我)
这意味着这意味着所示的程序违反了上述引用的陈述,因此不正确的诊断 。
也可以在 temp.spec.spec :
(强调矿山)
这再次得出结论,即给定的示例程序是 ndr。
因此,只要ETI定义在整个程序中仅出现一次,该程序是有效的。例如,如果您的标头具有具有ETI定义的标题,则如果将标头包含在一个以上的源文件中,则该程序将不正确(请注意此在这里)。但是,如果将标题包含在一个源文件中,则该程序将被构成良好。 重点是他们最多应该在程序中出现。它们来自(例如标题或源文件)是无关紧要的。
From explicit instantiation's documentation:
(emphasis mine)
This means that the shown program in question is in violation of the above quoted statement and thus ill-formed no diagnostic required.
The same can be found in temp.spec:
(emphasis mine)
This again leads to the conclusion that the given example program is ill-formed NDR.
Thus as long as the ETI definition occurs only once in the entire program the program is valid. For example, if you have a header that has the ETI definitions, then the program will be ill-formed if that header is included in more than one source file(note a possible workaround for this here). But if the header is included in exactly one source file then the program will be well-formed. The point is that they should appear at most once in the program. From where they come from(like header or a source file) is irrelevant.