模板化双模板 class 方法
Templating a double-templated class method
这是我的简化代码:
template<typename device, template<typename device> class protocol>
class MyClass
{
public:
template<typename select>
bool method()
{
// Code
}
};
我希望 method
在 protocol
类型方面表现不同。
换句话说,我有两种不同的可能协议,我想根据这些协议为我的方法提供两种不同的行为。但是不知道怎么用模板写。
例如,使用 SFINAE(如果您接受 C++11 解决方案)
#include <iostream>
#include <type_traits>
template <typename>
struct protocol_1
{ };
template <typename>
struct protocol_2
{ };
template<typename device, template<typename> class protocol>
class MyClass
{
public:
template<typename select, typename p = protocol<device>>
typename std::enable_if<
std::is_same<p, protocol_1<device>>::value, bool>::type
method()
{ return true; }
template<typename select, typename p = protocol<device>>
typename std::enable_if<
std::is_same<p, protocol_2<device>>::value, bool>::type
method()
{ return false; }
};
int main()
{
MyClass<int, protocol_1> m1;
MyClass<int, protocol_2> m2;
std::cout << m1.method<int>() << std::endl; // print 1 (true)
std::cout << m2.method<void>() << std::endl; // print 0 (false)
}
--- 编辑 ---
正如 Yakk 所指出的(谢谢!),这个解决方案很弱,因为使用了一个可以显式和规避的模板默认值。
一个例子;
MyClass<int, protocol_1>{}.method<void>();
被称为method()
的"protocol_1"版本,使用p
的默认值; but explciting p
, 如下
MyClass<int, protocol_1>{}.method<void, protocol_2<int>>();
被称为 method()
的 "protocol_2" 版本,基于 protocol_1
的 MyClass
版本
为避免此问题,可以在 method()
的两个版本中添加 static_assert()
,以检查并强制 p
等于其默认值(protocol<device>
)
我的意思是...如下
template<typename select, typename p = protocol<device>>
typename std::enable_if<
std::is_same<p, protocol_1<device>>::value, bool>::type
method()
{
static_assert(std::is_same<p, protocol<device>>::value, "!");
return true;
}
template<typename select, typename p = protocol<device>>
typename std::enable_if<
std::is_same<p, protocol_2<device>>::value, bool>::type
method()
{
static_assert(std::is_same<p, protocol<device>>::value, "!");
return false;
}
所以
MyClass<int, protocol_1>{}.method<void, protocol_2<int>>();
生成编译器错误。
使用外部助手是另一种可能的解决方案:
template <typename T>
struct B {
};
template <template<typename> class protocol, typename select>
struct helper {
static bool do_real() {
return true;
}
};
template <typename select>
struct helper<B, select> {
static bool do_real() {
return false;
}
};
template<typename device, template<typename> class protocol>
class MyClass
{
public:
template<typename select>
bool method()
{
return helper<protocol, select>::do_real();
}
};
喜欢this
您可以部分特化 class,例如:
template<typename device, template<typename> class protocol>
class MyClass;
template <typename> struct protocole1 { /* ... */ };
template <typename> struct protocole2 { /* ... */ };
template<typename device>
class MyClass<device, protocol1>
{
public:
template<typename select>
bool method()
{
// Code for protocole1
}
};
template<typename device>
class MyClass<device, protocol2>
{
public:
template<typename select>
bool method()
{
// Code for protocole2
}
};
你没有说哪个是目标标准,我尽量给你一个四季皆宜的替代方案。
在 C++11/14 中,您可以使用标记分派和函数重载来执行此操作。
它遵循一个最小的工作示例:
#include<iostream>
template<typename> struct protocol_a {};
template<typename> struct protocol_b {};
template<typename device, template<typename> class protocol>
class MyClass {
template<template<typename> class> struct tag {};
template<typename select>
bool method(tag<protocol_a>) {
std::cout << "protocol_a" << std::endl;
return true;
}
template<typename select>
bool method(tag<protocol_b>) {
std::cout << "protocol_b" << std::endl;
return false;
}
public:
template<typename select>
bool method() {
return method<device>(tag<protocol>{});
}
};
int main() {
MyClass<int, protocol_a> mca;
mca.method<void>();
MyClass<int, protocol_b> mcb;
mcb.method<void>();
}
非常紧凑。它不需要额外的 类、偏特化或 sfinae 表达式。 缺点(如果我们可以称其为缺点)是你多了一层间接。
在 C++17 中,您可以使用 if constexpr
获得相同的结果。
它遵循一个最小的工作示例:
#include<type_traits>
#include<iostream>
template<typename> struct protocol_a {};
template<typename> struct protocol_b {};
template<typename device, template<typename> class protocol>
class MyClass {
public:
template<typename select>
bool method() {
if constexpr(std::is_same_v<protocol<device>, protocol_a<device>>) {
std::cout << "protocol_a" << std::endl;
return true;
} else if constexpr(std::is_same_v<protocol<device>, protocol_b<device>>) {
std::cout << "protocol_b" << std::endl;
return false;
}
}
};
int main() {
MyClass<int, protocol_a> mca;
mca.method<void>();
MyClass<int, protocol_b> mcb;
mcb.method<void>();
}
更紧凑,但不能选择 C++17。
在 wandbox 上查看 运行。
这是我的简化代码:
template<typename device, template<typename device> class protocol>
class MyClass
{
public:
template<typename select>
bool method()
{
// Code
}
};
我希望 method
在 protocol
类型方面表现不同。
换句话说,我有两种不同的可能协议,我想根据这些协议为我的方法提供两种不同的行为。但是不知道怎么用模板写。
例如,使用 SFINAE(如果您接受 C++11 解决方案)
#include <iostream>
#include <type_traits>
template <typename>
struct protocol_1
{ };
template <typename>
struct protocol_2
{ };
template<typename device, template<typename> class protocol>
class MyClass
{
public:
template<typename select, typename p = protocol<device>>
typename std::enable_if<
std::is_same<p, protocol_1<device>>::value, bool>::type
method()
{ return true; }
template<typename select, typename p = protocol<device>>
typename std::enable_if<
std::is_same<p, protocol_2<device>>::value, bool>::type
method()
{ return false; }
};
int main()
{
MyClass<int, protocol_1> m1;
MyClass<int, protocol_2> m2;
std::cout << m1.method<int>() << std::endl; // print 1 (true)
std::cout << m2.method<void>() << std::endl; // print 0 (false)
}
--- 编辑 ---
正如 Yakk 所指出的(谢谢!),这个解决方案很弱,因为使用了一个可以显式和规避的模板默认值。
一个例子;
MyClass<int, protocol_1>{}.method<void>();
被称为method()
的"protocol_1"版本,使用p
的默认值; but explciting p
, 如下
MyClass<int, protocol_1>{}.method<void, protocol_2<int>>();
被称为 method()
的 "protocol_2" 版本,基于 protocol_1
MyClass
版本
为避免此问题,可以在 method()
的两个版本中添加 static_assert()
,以检查并强制 p
等于其默认值(protocol<device>
)
我的意思是...如下
template<typename select, typename p = protocol<device>>
typename std::enable_if<
std::is_same<p, protocol_1<device>>::value, bool>::type
method()
{
static_assert(std::is_same<p, protocol<device>>::value, "!");
return true;
}
template<typename select, typename p = protocol<device>>
typename std::enable_if<
std::is_same<p, protocol_2<device>>::value, bool>::type
method()
{
static_assert(std::is_same<p, protocol<device>>::value, "!");
return false;
}
所以
MyClass<int, protocol_1>{}.method<void, protocol_2<int>>();
生成编译器错误。
使用外部助手是另一种可能的解决方案:
template <typename T>
struct B {
};
template <template<typename> class protocol, typename select>
struct helper {
static bool do_real() {
return true;
}
};
template <typename select>
struct helper<B, select> {
static bool do_real() {
return false;
}
};
template<typename device, template<typename> class protocol>
class MyClass
{
public:
template<typename select>
bool method()
{
return helper<protocol, select>::do_real();
}
};
喜欢this
您可以部分特化 class,例如:
template<typename device, template<typename> class protocol>
class MyClass;
template <typename> struct protocole1 { /* ... */ };
template <typename> struct protocole2 { /* ... */ };
template<typename device>
class MyClass<device, protocol1>
{
public:
template<typename select>
bool method()
{
// Code for protocole1
}
};
template<typename device>
class MyClass<device, protocol2>
{
public:
template<typename select>
bool method()
{
// Code for protocole2
}
};
你没有说哪个是目标标准,我尽量给你一个四季皆宜的替代方案。
在 C++11/14 中,您可以使用标记分派和函数重载来执行此操作。
它遵循一个最小的工作示例:
#include<iostream>
template<typename> struct protocol_a {};
template<typename> struct protocol_b {};
template<typename device, template<typename> class protocol>
class MyClass {
template<template<typename> class> struct tag {};
template<typename select>
bool method(tag<protocol_a>) {
std::cout << "protocol_a" << std::endl;
return true;
}
template<typename select>
bool method(tag<protocol_b>) {
std::cout << "protocol_b" << std::endl;
return false;
}
public:
template<typename select>
bool method() {
return method<device>(tag<protocol>{});
}
};
int main() {
MyClass<int, protocol_a> mca;
mca.method<void>();
MyClass<int, protocol_b> mcb;
mcb.method<void>();
}
非常紧凑。它不需要额外的 类、偏特化或 sfinae 表达式。 缺点(如果我们可以称其为缺点)是你多了一层间接。
在 C++17 中,您可以使用 if constexpr
获得相同的结果。
它遵循一个最小的工作示例:
#include<type_traits>
#include<iostream>
template<typename> struct protocol_a {};
template<typename> struct protocol_b {};
template<typename device, template<typename> class protocol>
class MyClass {
public:
template<typename select>
bool method() {
if constexpr(std::is_same_v<protocol<device>, protocol_a<device>>) {
std::cout << "protocol_a" << std::endl;
return true;
} else if constexpr(std::is_same_v<protocol<device>, protocol_b<device>>) {
std::cout << "protocol_b" << std::endl;
return false;
}
}
};
int main() {
MyClass<int, protocol_a> mca;
mca.method<void>();
MyClass<int, protocol_b> mcb;
mcb.method<void>();
}
更紧凑,但不能选择 C++17。
在 wandbox 上查看 运行。