C++ 模板类的非模板方法的早期实例化
考虑以下类别:C++ 模板类的非模板方法的早期实例化,c++,c++17,language-lawyer,c++20,C++,C++17,Language Lawyer,C++20,考虑以下类别: #include <vector> template<class T> struct my_struct { my_struct() {} explicit my_struct(T) {} explicit my_struct(std::vector<T>) {} }; int main() { my_struct<const int> s1(1); } 正如我解释的那样,问题在于一旦实
#include <vector>
template<class T>
struct my_struct {
my_struct() {}
explicit my_struct(T) {}
explicit my_struct(std::vector<T>) {}
};
int main() {
my_struct<const int> s1(1);
}
正如我解释的那样,问题在于一旦实例化了my_struct
,就会产生一个具体的类型,编译器可能会实例化它的所有方法。在本例中,它实例化了myu结构(myu类)
,因此它实例化了myu类
,因此我们得到了静态错误
注意:我们可能会得到“幸运”但是:在vector
情况下,只调用my_struct()
不会触发错误(我想这与重载解析有关)
注意:我修复错误的方法是通过模板化构造函数,而不是使用vector
:
template<class vector_type>
my_struct(vector_type) {}
模板
my_结构(向量_类型){}
我觉得很难看,但没有其他想法
当
T
为const
时,可以使用std::enable_if
禁用向量构造函数:
#include <type_traits>
#include <vector>
template<class T>
struct my_struct {
my_struct() {}
explicit my_struct(T) {}
template <typename U = T>
explicit my_struct(std::vector<U>, std::enable_if_t<!std::is_const_v<U>, int> = 0) {}
};
int main() {
my_struct<const int> s(1);
my_struct<int> t({1, 2});
}
#包括
#包括
模板
结构我的结构{
my_struct(){}
显式my_结构(T){}
模板
显式my_结构(std::vector,std::enable_if_t,int>=0){
};
int main(){
我的结构(1);
我的结构t({1,2});
}
从C++20开始,您可以使用尾部requires子句引入的约束表达式,将my_struct
类模板的给定实例化的第三个构造函数的实例化约束到类模板的类型模板参数T
上的某个谓词:
#include <type_traits>
#include <vector>
template<class T>
struct my_struct {
my_struct() {}
explicit my_struct(T) {}
explicit my_struct(std::vector<T>) requires (!std::is_const_v<T>) {}
};
int main() {
my_struct<const int> s(1);
my_struct<int> t({1, 2});
}
#包括
#包括
模板
结构我的结构{
my_struct(){}
显式my_结构(T){}
显式my_结构(std::vector)需要(!std::is_const_v){}
};
int main(){
我的结构(1);
我的结构t({1,2});
}
除了使用比C++20之前版本更简单的语法之外,std::enable_if_tSFINAE方法,它也不会强制您仅将构造函数设置为模板函数,这样当构造函数是重载解析中的候选函数时,构造函数本身就可以通过参与推断过程的类型模板参数进行参数化
特别是,国家[强调我国]:
[temp.constr.constr]/2
为了实例化受约束的模板
([temp.spec]),应满足其相关约束条件
在以下子条款中描述。[注:形成一个
类模板、变量模板或别名的专门化
模板([temp.names])需要满足其约束条件。
重载解决方案需要满足函数和函数模板的约束条件。结束注释]
在这种情况下,特定的相关约束包括:
[temp.constr.decl]/3
声明的关联约束定义如下:
- [……]
- (3.3)否则,相关约束是逻辑AND表达式的标准形式,其操作数顺序如下:
- [……]
- (3.3.4)函数声明([dcl.fct])的尾随requires子句([dcl.decl])引入的约束表达式
1)
static_断言(0,“不应使用”)代码>是,这与std::vector
无关。2) 我建议您也添加语言标准标签。例如,C++17和C++20的解决方案可能会有所不同。我曾经得出结论,一个实现是有权利的,因为它的约束会影响程序的有效性。您似乎也遇到了类似的情况,尽管GCC在通过引用传递向量时并不担心。这就是问题所在。@Evg同时添加了C++17和C++20,因为我想要这两个的答案obviously@LanguageLawyer:必须实例化参数类型以执行重载解析,因为它可能可以从参数类型构造。(通过引用,允许实现跳过实例化([temp.inst]/9)。)您可能想说这里需要额外的模板参数。
#include <type_traits>
#include <vector>
template<class T>
struct my_struct {
my_struct() {}
explicit my_struct(T) {}
explicit my_struct(std::vector<T>) requires (!std::is_const_v<T>) {}
};
int main() {
my_struct<const int> s(1);
my_struct<int> t({1, 2});
}