如何在C++中对模板类的模板方法进行部分规范?

问题描述 投票:0回答:1

我尝试创建一个类方法,仅当静态条件为真时才执行部分代码。否则它不应该被执行,甚至不应该被编译。下面是我尝试制作的代码的简化变体:

#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 <>
,但无论如何都不起作用。如何让它发挥作用?

c++ class templates
1个回答
0
投票
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);
}
© www.soinside.com 2019 - 2024. All rights reserved.