在尝试调用接受一个类型和该类型的参数/参数作为模板参数/参数的功能模板时,编译器给出了一个错误,该错误不会由相似的参数/参数产生。因此,我想知道为矢量类的成员函数“ operator [] const”调用函数模板时,正确的参数/参数是什么!
考虑这段代码:
class test_class{
public:
int member;
int& operator[](size_t) {return member;}
const int& operator[](size_t) const{return member;}
};
typedef std::vector<int> vector_type;
typedef const int&(test_class::* OK_type)(size_t)const;
typedef const int&(vector_type::* not_OK_type)(size_t)const;
static constexpr OK_type OK_pointer = &test_class::operator[];
static constexpr not_OK_type not_OK_pointer = &vector_type::operator[];
template<typename t__, t__>
void function(){}
上面的代码现在可以考虑主要功能:
int main() {
function<OK_type, OK_pointer>();
function<not_OK_type, not_OK_pointer>();
return 0;
}
函数模板的第一个调用可以,但是第二个则不能。 编译器产生的错误是:
error: no matching function for call to ‘function<not_OK_type, not_OK_pointer>()’
note: candidate: ‘template<class t__, t__ <anonymous> > void function()’
note: template argument deduction/substitution failed:
error: ‘const int& (std::vector<int>::*)(size_t) const{((const int& (std::vector<int>::*)(size_t) const)std::vector<int>::operator[]), 0}’ is not a valid template argument for type ‘const int& (std::vector<int>::*)(long unsigned int) const’
function<not_OK_type, not_OK_pointer>();
note: it must be a pointer-to-member of the form ‘&X::Y’
有趣的是,即使功能模板的格式如下:
template<auto>
void function(){}
这将导致相同的结果。
我必须补充一点,在非const版本的情况下,错误是相同的(对于std::vector
)。
所以我想知道
A:怎么了?
B:考虑到如果not_OK_type
和&vector_type::operator[]
之间不匹配,那么在以下情况下,编译器也会给出错误消息:
static constexpr not_OK_type not_OK_pointer = &vector_type::operator[];
可用作constexpr的类型与可用作模板参数/参数的类型之间是否有区别?
答案 0 :(得分:2)
问题是typedef const int&(vector_type::* not_OK_type)(size_t)const;
。
如果看到stl_vector.h
(here),则在第1040行将operator []声明为noexcept
。
但是在not_OK_type
变量的声明中,noexcept
不存在。这就是编译器抱怨的原因。
要摆脱编译错误,请将noexcept
添加到not_OK_type
变量中。像这样:
typedef const int&(vector_type::* not_OK_type)(size_t)const noexcept;
工作代码:
#include <vector>
class test_class{
public:
int member;
int& operator[](size_t) {return member;}
const int& operator[](size_t) const{return member;}
};
typedef std::vector<int> vector_type;
typedef const int&(test_class::* OK_type)(size_t)const;
typedef const int&(vector_type::* not_OK_type)(size_t)const noexcept;
static constexpr OK_type OK_pointer = &test_class::operator[];
static constexpr not_OK_type not_OK_pointer = &vector_type::operator[];
template<typename t__, t__>
void function(){}
int main() {
function<OK_type, OK_pointer>();
function<not_OK_type, not_OK_pointer>();
return 0;
}
答案 1 :(得分:0)
@Kunal Puri,为问题的A部分提供了正确答案。
对于问题的B部分,我猜想线索可以在一个例外中找到,该例外适用于转换后的常量表达式用作非类型模板参数。
根据(https://en.cppreference.com/w/cpp/language/constant_expression),在特定条件下,特别是在将指针从noexcept函数转换为函数指针的情况下,转换后的常量表达式是一个常量表达式。这就解释了为什么在以下情况下编译器不会产生错误:
static constexpr not_OK_type not_OK_pointer = &vector_type::operator[];
但是根据(https://en.cppreference.com/w/cpp/language/template_parameters),这种类型的转换后的常量表达式不能用作非静态数据成员的指针(也可能是非静态成员函数的指针)类型模板参数。
此异常可能是可以用作 constexpr 和 template参数的类型之间冲突的根源,尽管后面的源代码中的语句含糊且未直接链接视情况而定。