0

以下代码有效

struct A
{
   int v = 3;
};

namespace Foo
{
   template <int k=11>
   int operator+(A const& lhs, A const& rhs)
   {
      return lhs.v + rhs.v + k;
   }
}

using Foo::operator+;

int main()
{
   A a1, a2;
   std::cout << a1 + a2 << std::endl;
   return 0;
}

using Foo::operator+;指令带入Foo::operator+外部查找范围,并且operator+在调用中使用时cout,采用默认模板值 11,结果如预期的那样:17 (=3+3+11)。

我的问题是如何更改using子句以使用默认模板值显式实例化operator+函数?

线路using Foo::operator+<42>不工作。
这是由于 ISO C++ 标准 7.3.3.5:使用声明不应命名模板 ID。
有没有解决的办法?

4

2 回答 2

2

回答自己...
问题似乎源于 ISO C++ 标准 7.3.3.5:

using-declaration 不应命名模板 ID。

这会阻止接受:using Foo::operator+<42>.

作为一种解决方法,我发现以下解决方案可以满足我的需要,但代价是额外的命名空间重定向。代码可能仍需要一些按摩,但它确实可以在用户端以最少的重复完成任务。

在此处查看工作版本。

struct A
{
   int v = 0;
};

template <int k>
struct Bar
{
   static int plus(A const& lhs, A const& rhs)
   {
      return rhs.v + lhs.v + k;
   }
};
    
namespace Boo
{
   using Baz = Bar<42>; // same as `typedef Bar<42> Baz;`

    //#include "foo_operators.h"
    namespace Foo
    {
       int operator+(A const& rhs, A const& lhs)
       {
          return Baz::plus(lhs, rhs);
       }
    }
}

namespace Goo
{
   using Baz = Bar<3>; 

    //#include "foo_operators.h"
    namespace Foo
    {
       int operator+(A const& rhs, A const& lhs)
       {
          return Baz::plus(lhs, rhs);
       }
    }
}


using namespace std;
int main()
{
   {
      using Boo::Foo::operator+;
      A a1, a2;
      cout << a1 + a2 << endl;
   }

   {
      using Goo::Foo::operator+;
      A a1, a2;
      cout << a1 + a2 << endl;
   }

   return EXIT_SUCCESS;
}

// In real code extract to foo_operators.h: the partial file snippets to get #included multiple times
// namespace Foo
// {
//    int operator+(A const& rhs, A const& lhs)
//    {
//       return Baz::plus(lhs, rhs);
//    }
// }

这个想法是Foo用带有静态方法的结构模板替换命名空间Bar。这允许使用所需的参数
来实例化类型。 运算符只需通​​过外部定义和参数化的类型调用静态方法。 ADL 负责其余的工作。Foo

在上面的示例中,用户创建了 2 个新的命名空间,BooGoo具有 2 个不同的加号运算符参数化。最后,在使用时,用户会带入所需版本operator+using directive.

在这种方法中,似乎没有指定默认参数值的选项。

在实际代码中,运算符本身将存储在一个片段文件中,以便在声明参数化类型(在示例中)#include之后编辑到代码中。Baz

拿 2

这是一个更简洁的版本,它使用了一个简单的模板化特征类,并避免了额外的命名空间和操作符重定向功能plus

template <int k>
struct op_traits_t
{
   static const int K = k;
};


namespace Boo
{
   using op_traits = op_traits_t<42>; // same as `typedef op_traits_t<42> op_traits;`
   //#include "foo_operators.h"
    // this is a partial file snippet
    int operator+(A const& rhs, A const& lhs)
    {
       return rhs.v + lhs.v + op_traits::K; 
    }
}

namespace Goo
{
   using op_traits = op_traits_t<3>;
   //#include "foo_operators.h"
    // this is a partial file snippet
    int operator+(A const& rhs, A const& lhs)
    {
       return rhs.v + lhs.v + op_traits::K; 
    }
}

int main()
{
   {
      using Boo::operator+;
      A a1, a2;
      cout << a1 + a2 << endl;
   }

   {
      using namespace Goo;
      A a1, a2;
      cout << a1 + a2 << endl;
   }

   return EXIT_SUCCESS;
}
于 2016-04-28T09:58:01.737 回答
1
std::cout << operator+<12>(a1, a2) << std::endl;

但不要这样做。运算符 + 应该以一种不出所料的方式表现。

使用命名函数:

namespace Foo
{
   template <int k=11>
   int add_plus_k(A const& lhs, A const& rhs)
   {
      return lhs.v + rhs.v + k;
   }
}
于 2016-04-27T15:35:43.143 回答