如何类型转换为模板成员函数参数?
How to type-cast as template member function parameter?
我实施了 class 模板 writer
。 writer
有模板成员变量 s_
。 s_
的类型是 Stream
。 writer
期望 Stream
有一个可以使用参数 const char* buf
和 size_t len
.
调用的成员函数
这是writer
的第一个版本:
// clang++ -Wconversion test.cpp
#include <cstddef>
#include <ostream>
template <class F> struct size_arg_type;
template <typename Ret, typename Cls, typename T1, typename T2>
struct size_arg_type<Ret (Cls::*)(T1, T2)> {
using type = T2;
};
template <typename Stream>
struct writer {
writer(Stream& s):s_(s) {}
void write(const char* buf, size_t len) {
// The type of 2nd parameter depends on Stream
s_.write(buf, len);
}
Stream& s_;
};
struct user_stream1 {
void write(const char*, size_t) {}
};
struct user_stream2 {
void write(const char*, std::streamsize) {}
};
struct user_stream3 {
void write(const char*, size_t) {}
void write() {}
};
#include <sstream>
int main() {
{ // size_type is size_t
user_stream1 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
{ // size_type is std::streamsize
user_stream2 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
#if 1
{ // size_type is size_t but has overloaded member function
user_stream3 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
#endif
{ // size_type is std::streamsize return type is std::ostream&
std::stringstream s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
}
运行 演示:https://wandbox.org/permlink/JtEHDG3plWxe4vwB
如果我将 -Wconversion
标志设置为 clang++,我会收到以下警告。
clang++ -std=c++17 -Wconversion test.cpp
test.cpp:18:23: warning: implicit conversion changes signedness: 'size_t' (aka 'unsigned long') to
'std::streamsize' (aka 'long') [-Wsign-conversion]
s_.write(buf, len);
~~~~~ ^~~
test.cpp:50:11: note: in instantiation of member function 'writer<user_stream2>::write' requested here
w.write(buf, sizeof(buf));
^
test.cpp:18:23: warning: implicit conversion changes signedness: 'size_t' (aka 'unsigned long') to
'std::streamsize' (aka 'long') [-Wsign-conversion]
s_.write(buf, len);
~~~~~ ^~~
test.cpp:64:11: note: in instantiation of member function 'writer<std::__cxx11::basic_stringstream<char>
>::write' requested here
w.write(buf, sizeof(buf));
^
2 warnings generated.
Compilation finished at Wed May 1 09:37:37
我试图找到一种无需 pragma 即可抑制警告的方法。
我想出了 static_cast
方法。为了执行 static_cast
,我需要知道第二个参数类型。
所以我实现了一些参数类型提取器:
// clang++ -std=c++17 -Wconversion test.cpp
#include <cstddef>
#include <ostream>
template <class F> struct size_arg_type;
template <typename Ret, typename Cls, typename T1, typename T2>
struct size_arg_type<Ret (Cls::*)(T1, T2)> {
using type = T2;
};
template <typename Stream>
struct writer {
writer(Stream& s):s_(s) {}
void write(const char* buf, size_t len) {
write_impl(&Stream::write, buf, len);
}
template <typename Write>
void write_impl(Write, const char* buf, size_t len)
{
s_.write(buf, static_cast<typename size_arg_type<Write>::type>(len));
}
Stream& s_;
};
struct user_stream1 {
void write(const char*, size_t) {}
};
struct user_stream2 {
void write(const char*, std::streamsize) {}
};
struct user_stream3 {
void write(const char*, size_t) {}
void write() {}
};
#include <sstream>
int main() {
{ // size_type is size_t
user_stream1 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
{ // size_type is std::streamsize
user_stream2 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
#if 1
{ // size_type is size_t but has overloaded member function
user_stream3 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
#endif
{ // size_type is std::streamsize return type is std::ostream&
std::stringstream s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
}
如我所料。但是在user_stream3
重载了write()
成员函数的情况下,出现了编译错误。
运行 演示:https://wandbox.org/permlink/TDPlQ3nXzIKjSlhY
为了获得成员函数的特定重载,我需要知道完整的成员函数指针类型。然而,世事难料。
clang++ -std=c++17 -Wconversion test.cpp
test.cpp:18:9: error: no matching member function for call to 'write_impl'
write_impl(&Stream::write, buf, len);
^~~~~~~~~~
test.cpp:63:11: note: in instantiation of member function 'writer<user_stream3>::write' requested here
w.write(buf, sizeof(buf));
^
test.cpp:22:10: note: candidate template ignored: couldn't infer template argument 'Write'
void write_impl(Write, const char* buf, size_t len)
^
1 error generated.
Compilation exited abnormally with code 1 at Wed May 1 09:48:42
有没有什么好的方法可以知道大小类型,或者在没有 pragma 的情况下抑制警告?
在你的第二个版本中取写函数的地址时,它不知道取哪个重载的地址。您需要充分限制您的模板参数,以便重载不会模棱两可:
template <typename Stream>
struct writer {
writer(Stream& s):s_(s) {}
void write(const char* buf, size_t len) {
write_impl(&Stream::write, buf, len);
}
template <typename Ret, typename Cls, typename T1, typename T2>
void write_impl(Ret (Cls::*)(T1, T2), const char* buf, size_t len)
{
s_.write(buf, static_cast<T2>(len));
}
Stream& s_;
};
https://wandbox.org/permlink/7Qb6xAoUQPRz3o2u
然而,如果有多个 2-argument write
函数,这仍然会失败。在这种情况下,您将不得不找到更多约束(例如,第一个参数必须是 const char *
)或者只需要用户代码的特定签名。
我实施了 class 模板 writer
。 writer
有模板成员变量 s_
。 s_
的类型是 Stream
。 writer
期望 Stream
有一个可以使用参数 const char* buf
和 size_t len
.
这是writer
的第一个版本:
// clang++ -Wconversion test.cpp
#include <cstddef>
#include <ostream>
template <class F> struct size_arg_type;
template <typename Ret, typename Cls, typename T1, typename T2>
struct size_arg_type<Ret (Cls::*)(T1, T2)> {
using type = T2;
};
template <typename Stream>
struct writer {
writer(Stream& s):s_(s) {}
void write(const char* buf, size_t len) {
// The type of 2nd parameter depends on Stream
s_.write(buf, len);
}
Stream& s_;
};
struct user_stream1 {
void write(const char*, size_t) {}
};
struct user_stream2 {
void write(const char*, std::streamsize) {}
};
struct user_stream3 {
void write(const char*, size_t) {}
void write() {}
};
#include <sstream>
int main() {
{ // size_type is size_t
user_stream1 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
{ // size_type is std::streamsize
user_stream2 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
#if 1
{ // size_type is size_t but has overloaded member function
user_stream3 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
#endif
{ // size_type is std::streamsize return type is std::ostream&
std::stringstream s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
}
运行 演示:https://wandbox.org/permlink/JtEHDG3plWxe4vwB
如果我将 -Wconversion
标志设置为 clang++,我会收到以下警告。
clang++ -std=c++17 -Wconversion test.cpp
test.cpp:18:23: warning: implicit conversion changes signedness: 'size_t' (aka 'unsigned long') to
'std::streamsize' (aka 'long') [-Wsign-conversion]
s_.write(buf, len);
~~~~~ ^~~
test.cpp:50:11: note: in instantiation of member function 'writer<user_stream2>::write' requested here
w.write(buf, sizeof(buf));
^
test.cpp:18:23: warning: implicit conversion changes signedness: 'size_t' (aka 'unsigned long') to
'std::streamsize' (aka 'long') [-Wsign-conversion]
s_.write(buf, len);
~~~~~ ^~~
test.cpp:64:11: note: in instantiation of member function 'writer<std::__cxx11::basic_stringstream<char>
>::write' requested here
w.write(buf, sizeof(buf));
^
2 warnings generated.
Compilation finished at Wed May 1 09:37:37
我试图找到一种无需 pragma 即可抑制警告的方法。
我想出了 static_cast
方法。为了执行 static_cast
,我需要知道第二个参数类型。
所以我实现了一些参数类型提取器:
// clang++ -std=c++17 -Wconversion test.cpp
#include <cstddef>
#include <ostream>
template <class F> struct size_arg_type;
template <typename Ret, typename Cls, typename T1, typename T2>
struct size_arg_type<Ret (Cls::*)(T1, T2)> {
using type = T2;
};
template <typename Stream>
struct writer {
writer(Stream& s):s_(s) {}
void write(const char* buf, size_t len) {
write_impl(&Stream::write, buf, len);
}
template <typename Write>
void write_impl(Write, const char* buf, size_t len)
{
s_.write(buf, static_cast<typename size_arg_type<Write>::type>(len));
}
Stream& s_;
};
struct user_stream1 {
void write(const char*, size_t) {}
};
struct user_stream2 {
void write(const char*, std::streamsize) {}
};
struct user_stream3 {
void write(const char*, size_t) {}
void write() {}
};
#include <sstream>
int main() {
{ // size_type is size_t
user_stream1 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
{ // size_type is std::streamsize
user_stream2 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
#if 1
{ // size_type is size_t but has overloaded member function
user_stream3 s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
#endif
{ // size_type is std::streamsize return type is std::ostream&
std::stringstream s;
writer w(s);
char buf[] = "123";
w.write(buf, sizeof(buf));
}
}
如我所料。但是在user_stream3
重载了write()
成员函数的情况下,出现了编译错误。
运行 演示:https://wandbox.org/permlink/TDPlQ3nXzIKjSlhY
为了获得成员函数的特定重载,我需要知道完整的成员函数指针类型。然而,世事难料。
clang++ -std=c++17 -Wconversion test.cpp
test.cpp:18:9: error: no matching member function for call to 'write_impl'
write_impl(&Stream::write, buf, len);
^~~~~~~~~~
test.cpp:63:11: note: in instantiation of member function 'writer<user_stream3>::write' requested here
w.write(buf, sizeof(buf));
^
test.cpp:22:10: note: candidate template ignored: couldn't infer template argument 'Write'
void write_impl(Write, const char* buf, size_t len)
^
1 error generated.
Compilation exited abnormally with code 1 at Wed May 1 09:48:42
有没有什么好的方法可以知道大小类型,或者在没有 pragma 的情况下抑制警告?
在你的第二个版本中取写函数的地址时,它不知道取哪个重载的地址。您需要充分限制您的模板参数,以便重载不会模棱两可:
template <typename Stream>
struct writer {
writer(Stream& s):s_(s) {}
void write(const char* buf, size_t len) {
write_impl(&Stream::write, buf, len);
}
template <typename Ret, typename Cls, typename T1, typename T2>
void write_impl(Ret (Cls::*)(T1, T2), const char* buf, size_t len)
{
s_.write(buf, static_cast<T2>(len));
}
Stream& s_;
};
https://wandbox.org/permlink/7Qb6xAoUQPRz3o2u
然而,如果有多个 2-argument write
函数,这仍然会失败。在这种情况下,您将不得不找到更多约束(例如,第一个参数必须是 const char *
)或者只需要用户代码的特定签名。