这是我的简化代码:
template<typename device, template<typename device> class protocol>
class MyClass
{
public:
template<typename select>
bool method()
{
// Code
}
};
我希望method
在protocol
类型方面采取不同的行动。
换句话说,我有两种不同的可能协议,我希望根据协议为我的方法提供两种不同的行为。但我不知道如何用模板写它。
答案 0 :(得分:2)
你没有提到哪个是目标标准,所以我会尝试为你提供所有季节的替代品。
在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上运行。
答案 1 :(得分:1)
例如,使用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>();
被称为&#34; protocol_1&#34;版本method()
,使用p
的默认值;但请注明p
,如下
MyClass<int, protocol_1>{}.method<void, protocol_2<int>>();
被称为&#34; protocol_2&#34;基于method()
MyClass
的{{1}}版本的protocol_1
版本
要避免此问题,可以在static_assert()
的两个版本中添加method()
,以检查并强制p
等于其默认值({{ 1}})
我的意思是......如下:
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;
}
生成编译器错误。
答案 2 :(得分:1)
使用外部帮助是另一种可能的解决方案:
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
答案 3 :(得分:0)
您可以对该课程进行部分专业化,例如:
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
}
};