Следующий код работает:
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: Объявление использования не должно называть идентификатор шаблона.
Это можно обойти?
Отвечаю сам …
Кажется, что проблема связана с ISO C ++ Standard 7.3.3.5:
Объявление использования не должно называть идентификатор шаблона.
Это предотвращает принятие: 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
,
Это позволяет создавать экземпляры Foo
введите с помощью желаемых параметров.
Операторы просто вызывают статические методы через определенный и параметризованный тип.
ADL позаботится обо всем остальном.
В приведенном выше примере пользователь создал 2 новых пространства имен, Boo
а также Goo
иметь 2 разных параметризации оператора плюс. Наконец, в момент использования пользователь вводит желаемую версию operator+
с using directive
,
В этом подходе нет возможности указать значения параметров по умолчанию.
В реальном коде сами операторы будут храниться в файле сниппета для #include
в код после объявления параметризованного типа (Baz
в примере).
Вот гораздо более чистая версия, которая использует простой класс шаблонных признаков и избегает как дополнительного пространства имен, так и функции перенаправления оператора 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;
}
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;
}
}