编辑
您真正要求的是使编写代码成为错误,我很遗憾地说这实际上是不可能的。我不认为那里有一个 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
{
//...
};
一个好的解决方案是 templateClass1
的foo
方法,然后包含 a static_assert
,这是一个编译时断言。这是有效的,因为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
可能有一个成员变量j
. 只要该成员变量是constexpr
(并且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
此时,您将被降级为运行时异常处理:
template<int i>
struct Class1{
void foo(int j)
{
if (j%i != 0)
throw std::invalid_argument("j is not evenly divisible by i");
std::cout << "j is evenly divisble by i" << std::endl;
}
};
struct Class2
{
int j = 4;
void CallFoo()
{
Class1<2> c1;
c1.foo(j); // works
j = 3;
c1.foo(j); // throws
}
};
演示