我尝试创建一个类方法,仅当静态条件为真时才执行部分代码。否则它不应该被执行,甚至不应该被编译。下面是我尝试制作的代码的简化变体:
#include <cstdio>
#include <cstdint>
#include <type_traits>
class inet_socket {
uint32_t ip;
};
class unix_file_socket {
char path[64];
};
template <typename protocol>
class server
{
public:
protocol socket;
void do_something();
};
template <typename protocol>
void server<protocol>::do_something()
{
/* ... */
if (std::is_same<protocol, unix_file_socket>::value)
// use static check if protocol is unix file
// and if it is then delete file
std::remove(socket.path);
}
int main()
{
server<inet_socket> srv;
srv.do_something();
}
我认为如果
protocol
不是 unix_file_socket
那么编译器会排除 if (false)
语句,并且不会包含字符串 std::remove(socket.path)
,因此不会出现获取不存在的字段 path
的错误非 unix_file_socket
协议。但实际上我得到了一个错误:
file.cpp: In instantiation of ‘void server<protocol>::do_something() [with protocol = inet_socket]’:
file.cpp:33:22: required from here
file.cpp:27:28: error: ‘class inet_socket’ has no member named ‘path’
27 | std::remove(socket.path);
| ~~~~~~~^~~~
然后我尝试制作一个具有两个部分特化的模板方法。一个会删除文件,另一个则不会。然后我只会调用适合该协议的方法,因此它应该是为该协议编译的唯一方法,并且不应出现错误。变化:
template <typename protocol>
class server
{
public:
protocol socket;
void do_something();
template <bool> void remove_socket();
};
template <typename protocol>
void server<protocol>::do_something()
{
/* ... */
remove_socket<std::is_same<protocol, unix_file_socket>::value>();
// static check if protocol is unix file
// and if it is then use method that deletes file
// else use method that doesn't
}
template <typename protocol>
template <>
void server<protocol>::remove_socket<true>()
{
// if socket is unix file
std::remove(socket.path);
}
template <typename protocol>
template <>
void server<protocol>::remove_socket<false>()
{ /* if it is inet socket do nothing */ }
我希望它能起作用,但我遇到了语法错误:
file.cpp:34:11: error: invalid explicit specialization before ‘>’ token
34 | template <>
| ^
file.cpp:34:11: error: enclosing class templates are not explicitly specialized
file.cpp:42:11: error: invalid explicit specialization before ‘>’ token
42 | template <>
| ^
file.cpp:42:11: error: enclosing class templates are not explicitly specialized
我尝试擦除线条
template <>
,但无论如何都不起作用。如何让它发挥作用?
template <typename protocol> template <> void server<protocol>::remove_socket<true>()
这是根本不允许的(参见 [temp.expl.spec] p15)。 您不能定义非特化类的显式特化。 您可以有多个
template <>
,但不是您正在做的事情。
这里的基本问题是 C++ 中的显式专业化与非模板实体非常相似。 IE。
template <> foo<int>
的工作方式与 foo
非常相似,只是它有一些模板语法。 template <typename> typename <>
正在混合两个不能真正协同工作的结构。
如果你使用的是C++17,你可以简单地写:
template <typename protocol>
void server<protocol>::do_something()
{
/* ... */
if constexpr (std::is_same_v<protocol, unix_file_socket>)
std::remove(socket.path);
}
当条件为 false 时,if constexpr
将阻止实例化 std::remove
。
另请参阅 “if constexpr()”与“if()”之间的区别
在 C++17 之前,您还可以定义:
template <>
void server<unix_file_socket>::do_something()
{
/* ... */
std::remove(socket.path);
}