1

给定以下(伪)代码:

typedef std::map<const unsigned int, unsigned long int> ModelVector;
typedef std::vector<unsigned long int> EncryptedVector;

int test1 (const EncryptedVector &x)
{
    //compute ModelVector y
    data = kenel1(x, y);
    //compute output
}
int test2 (const EncryptedVector &xx)
{
    //compute ModelVector y
    data = kenel2(xx, y);
    //compute output
}
int test3 (const EncryptedVector &x, const EncryptedVector &xx)
{
    //compute ModelVector y
    data = kenel3(x, xx, y);
    //compute output
}
int test4 (const EncryptedVector &x, const EncryptedVector &xSquared)
{
    //compute ModelVector y
    data = kenel4(x, xSquared, y);
    //compute output
}

因为变量 y 和 output 在所有 4 个函数中的计算相同,并且由于我有一个“全局”对象,它允许我通过 switch 语句选择适当的内核函数,所以我想知道是否有更优雅的方式来编写它们,最好是以某种方式合并它们...

例如,像这样的东西(伪代码)将是一个不错的选择:

int test (const EncryptedVector &x, const EncryptedVector &xx, const EncryptedVector &xSquared)
{
    //compute ModelVector y
    //switch (kernel) -> select the appropriate one
    //compute output
}

test (x, NULL, NULL);//test1
test (NULL, xx, NULL);//test2
test (x, xx, NULL);//test3
test (x, NULL, xSquared);//test4

或者,更好的是,我可以使用不同的参数组合多次声明 test,所有这些都回退到上面的那个(即使我会失去 x 和 xx 之间的语义区别)。

上述方法的问题是 C++ 不允许我传递 NULL 而不是 std::vector ,我认为我最好重复代码 4 次而不是通过指针传递变量而不是通过引用传递它们。 ..

有没有其他方法可以做到这一点?


编辑:这是内核函数的原型:

int kernel1 (const EncryptedVector &x, const ModelVector &y);
int kernel2 (const EncryptedVector &xx, const ModelVector &y);
int kernel3 (const EncryptedVector &x, const EncryptedVector &xx, const ModelVector &y);
int kernel4 (const EncryptedVector &x, const EncryptedVector &xSquared, const ModelVector &y);
4

2 回答 2

4

您最初的 4 个方法不是根据传递的参数的类型,而是根据传递的参数的语义test来选择不同的行为(例如,kernel调用不同的函数)。更不用说他们有完全不同的名字这一事实。

如果您能以某种方式将此参数化从一种语义更改为一种类型,则可以使用您提出的将所有 4 种方法组合为一个的方法。

这意味着拥有一个具有所有 3 个参数的函数,这正是您所建议的:

int test (const EncryptedVector &x, const EncryptedVector &xx, const EncryptedVector &xSquared)

...问题当然是您不能通过NULL引用传递。你需要通过一个实际的vector. 您可以传递一个空的临时向量,如下所示:

test (x, EncryptedVector(), EncryptedVector());  //test1

...然后根据empty()传入的状态在内部选择方法vector

int test (const EncryptedVector &x, const EncryptedVector &xx, const EncryptedVector &xSquared)
{
    //compute ModelVector y
    //switch (kernel) -> select the appropriate one
      if( xx.empty() && xSquared.empty() )
      {
        // kenel1 method
      }
      else if( x.empty() && xSquared.empty() )
      {
        // kenel2 method
      }
      else if( ... etc ... )

    //compute output
}

也许对于您的使用来说,这已经足够了,但以上至少引发了几个新问题。

一是if陈述链。这引入了复杂性,无论是在执行时间的因素方面,还是在可维护性方面更重要的方面。我知道我不想保留 4 页的if声明。

其他问题包括使用空 s 笨拙地调用方法,以及您仍然可以使用无效的s组合vector调用这一事实。testvector

因此,回到使用基于类型的行为选择而不是语义选择。如果您没有为test()' 的参数指定具体类型,而是指定了 atemplate怎么办?

template<class VectorX, class VectorXX, class VectorXSquared>
int test(const VectorX& x, const VectorXX& xx, const VectorXSquared& xSquared);

现在你还可以提供一个特殊的NullVector类型:

class NullVector {}; // Empty Class

...然后test为您的每个有效用例明确专门化该功能(上面,您列出了 4 个有效用例)。

现在的调用test变成了这样:

test(x,NullVector(),NullVector());  // First Use Case

这还有一个额外的好处。如果您不提供非专用版本的实现test,则任何使用无效参数调用的尝试test都将无法编译和链接。例如,在您列出的用例中,它们都没有使用 3 个有效EncryptedVector对象,所以这应该无法编译:

test(x, xx, xSquared);

...确实,如果您不提供test.

好吧,说了这么多,也许没有得到很好的解释。所以这是一个完整的示例,我希望能帮助说明我在说什么:

#include <vector>
#include <string>
using namespace std;

typedef vector<string> EncryptedVector;

class NullVector{}; // Empty Class

int kernel1(const EncryptedVector& x)
{
    return 1;
}

int kernel2(const EncryptedVector& xx)
{
    return 2;
}

int kernel3(const EncryptedVector& x, const EncryptedVector& xx)
{
    return 3;
}

int kernel4(const EncryptedVector& x, const EncryptedVector& xSquared)
{
    return 4;
}

template<class VectorX, class VectorXX, class VectorXSquared> 
int test(const VectorX& x, const VectorXX& xx, const VectorXSquared& xSquared);

template<> int test<>(const EncryptedVector& x, const NullVector&, const NullVector&)
{
    return kernel1(x);
}

template<> int test<>(const NullVector&, const EncryptedVector& xx, const NullVector&)
{
    return kernel2(xx);
}

template<> int test<>(const EncryptedVector& x, const EncryptedVector& xx, const NullVector&)
{
    return kernel3(x, xx);
}

template<> int test<>(const EncryptedVector &x, const NullVector&, const EncryptedVector &xSquared)
{
    return kernel4(x,xSquared);
}

int main()
{
    EncryptedVector x, xx, xSquared;  // each somehow populated

    ///*** VALID USE-CASES ***///
    test(x,NullVector(),NullVector());
    test(NullVector(),xx,NullVector());
    test(x,xx,NullVector());
    test(x,NullVector(),xSquared);

    ///*** INVALID USE CASES WILL FAIL TO COMPILE&LINK ***///
    test(x,xx,xSquared);

}
于 2012-06-12T16:29:28.157 回答
0

您可以发送一个包含附加参数并具有计算内核(kenel?)的函数的对象(如果我没记错的话,它称为函子)。

// Main function, looks more generic now
template <class F>
int test1234(F functor)
{
    //compute ModelVector y
    data = functor(y);
    //compute output
}

...

// Functors involve some tedious coding, but at least your main calculation is clean
struct functor_for_kernel1
{
    const EncryptedVector &x;
    functor_for_kernel1(const EncryptedVector &x): x(x) {}
    int operator(const ModelVector &y) {return kernel1(x, y);
};

struct functor_for_kernel2 // easy
...

struct functor_for_kernel3
{
    const EncryptedVector &x, const EncryptedVector &xx;
    functor_for_kernel3(const EncryptedVector &x, const EncryptedVector &xx): x(x), xx(xx) {}
    int operator()(const ModelVector &y) {return kernel3(x, xx, y);
};

struct functor_for_kernel4 // easy
...

// Usage of the unified function
test1234(functor_for_kernel1(x));
test1234(functor_for_kernel2(xx));
test1234(functor_for_kernel3(x, xx));
test1234(functor_for_kernel4(x, xx));
于 2012-06-12T16:38:38.287 回答