这是我想要实现的简化示例。因此,它可能看起来有点傻但承担我。假设我有
template<int i>
class Class1{
foo(){cout<<"j is divisible by i, so we will hang out"<<endl;}
}
和class2
具有固定的int j
变量:由这样的int模板化或具有成员变量。我希望class2
个实例只有在满足某个条件时才能调用foo()
,在这种情况下,我想确保说(j%i==0)
。
我能想到的最好的是:
template<int i>
class Class1{
static const int intParam=i;
template<bool true>
foo(){cout<<"j is divisible by i, so we will hang out"<<endl;}
}
然后第2类会这样称呼它:
foo<class1::intParam%j>()
这不是很好。有没有更好的方法呢?我看到'std::enable_if'有点相关,但我不太确定。
如果你想要更大的图片,这是一个信号/代表经纪机制。在系统中,只有当执行者对象与任务中指定的角色枚举(int i
)匹配时,它们才能由执行者对象提供/请求。基本上这应该是没有动态多态性的基于枚举的设计。有没有更好的方法在C ++中执行此操作?
答案 0 :(得分:4)
template<int i, int j>
class Class1
{
public:
void foo()
{
static_assert(i % j == 0, "Message upon i % j == 0 being false");
cout<<"j is divisible by i, so we will hang out"<<endl;
}
};
并将其称为例如
Class1<42, 24> f;
f.foo();
更新评论,只需添加j
作为foo()
的额外模板参数:
template<int i>
class Class1
{
public:
template<int j>
void foo()
{
static_assert(i % j == 0, "Message upon i % j == 0 being false");
cout<<"j is divisible by i, so we will hang out"<<endl;
}
};
int main()
{
Class1<42> f;
f.foo<24>();
return 0;
}
答案 1 :(得分:2)
与其他解决方案相反,我建议使用SFINAE根据条件启用禁用功能。
template<int i>
struct Class1 {
template<int j, std::enable_if_t<i % j == 0>* = 0>
void foo() {
}
};
此解决方案的优点是,如果foo()
存在其他重载,编译器将尝试它们而不是给出硬错误。正如您在此Live Example所看到的,编译器给出的错误是:
main.cpp: In function 'int main()':
main.cpp:12:24: error: no matching function for call to 'Class1<3>::foo()'
Class1<3>{}.foo<2>();
^
这意味着错误发生在用户的代码中,而不是在标题中,并且如果有一个替代函数,当这个没有用时,编译器将尝试其他重载。
答案 2 :(得分:1)
你真正要求的是做的写的代码是一个错误,我很伤心地说,这不是真的有可能。我不认为有一个IDE会在字面上阻止你编写无效的代码。但是,如果您实现下面的一个解决方案(编译时的解决方案),那么一个足够高级的IDE将能够为您提供在编译之前您编写的代码不良的信息。
像Visual Studio这样的编译器本质上会在后台“编译”你的东西,然后用红色波浪线强调坏代码(读取:不会编译)。
您为Class2
结构建议了几种可能性,所以让我们解决每个问题:
首先,我们将根据您的定义开始Class1
:
template<int i>
struct Class1{
// how to define a "foo" function that is only callable
// if Class2's j is evenly divisble by i?
};
您的第一种可能性是Class2
有一个模板化的j
参数:
template<int j>
struct Class2
{
//...
};
一个很好的解决方案是模板Class1
的{{1}}方法,然后包含static_assert
,这是一个编译时断言。这是有效的,因为foo
和i
在编译时是已知的。
现在j
看起来像这样:
Class1
template<int i>
struct Class1{
template<int j>
void foo()
{
static_assert(j%i==0, "j is not evenly divisible by i");
std::cout << "j is evenly divisble by i" << std::endl;
}
};
可以这样调用Class2
:
foo
您提到的另一种可能性是template<int j>
struct Class2
{
void CallFoo()
{
Class1<2> c1;
c1.foo<j>(); // works
//Class1<3> c2;
//c2.foo<2>(); // fails static assert
}
};
可能有Class2
的成员变量。只要该成员变量为constexpr
(结果也是j
),您就可以完成此任务:
static
struct Class2
{
static constexpr int j = 4;
void CallFoo()
{
Class1<2> c1;
c1.foo<j>(); // works
//Class1<3> c2;
//c2.foo<2>(); // fails static assert
}
};
在此定义编译时常量。因此,保证在编译时知道该值,我们的constexpr
将起作用。
如果static_assert
不 j
,那么我们就无法实现编译时断言。此时,您将被降级为运行时异常处理:
constexpr