Как определить преобразование в шаблон класса, работающий при использовании в качестве аргумента функции - PullRequest
1 голос
/ 01 февраля 2020

Имея этот шаблон:

template <bool X> 
struct Foo {
  Foo(int v) : v(v) {}
  int v;
};

Я могу сказать, что по умолчанию Foo должно быть False с инструкцией по вычету:

Foo(int)->Foo<false>;

Спасибо за то, что этот код работает :

Foo a = 5;

Моя проблема в том, как мне сделать эту работу, когда Foo используется в качестве аргумента функции:

template <bool X> 
void f(Foo<X> foo) { 
  cout << "Foo<" << X << ">(" << foo.v << ")" << endl; 
}
f(5); // error: no matching function for call to 'f'
      // candidate template ignored: could not match 'Foo<X>' against 'int'

Я пытался как-то сказать f, что X по умолчанию false, но f (я имею в виду компилятор) меня не слушает:

template <bool X = false> // = false changes nothing, same error 
void f(Foo<X> foo) {
  cout << "Foo<" << X << ">(" << foo.v << ")" << endl; 
}
template <bool X> 
struct get_bool { // to force looking at f::X 
  static constexpr bool value = X; 
};

template <bool X = false> 
void f(Foo<get_bool<X>::value> foo) { 
  cout << "Foo<" << X << ">(" << foo.v << ")" << endl;         
  /* this is not working because 
   * get_bool evaulates before 
   * args matching and in the end, 
   * this function could be defined 
   * as: void f(Foo<false>) 
   */
}

Я не возражаю против введения некоторых дополнительных вспомогательных классов и т. Д. c , Я надеялся, что, возможно, некоторые decltype, auto, some_trait<> или дополнительный класс помощника (ов) маги c могли бы помочь здесь решить эту проблему, которую, я думаю, я также мог бы подытожить следующим образом: Как определить руководство по удержанию для функции?

1 Ответ

2 голосов
/ 01 февраля 2020

Проблема с template <bool X = false> void f(Foo<X> foo) заключается в том, что неявные преобразования не допускаются при передаче аргументов параметрам, которые используются при выводе параметров шаблона.

Вы можете либо добавить дополнительную перегрузку f, принимая int, либо не создавать f шаблон вообще:

struct Bar
{
    bool x = false;
    int v = 0;

    template <bool X>
    Bar(Foo<X> foo) : x(X), v(foo) {}

    Bar(int v) : v(v) {}
};

void f(Bar bar) {...}

Это означает, что логическое значение больше не является constexpr внутри f. Если вы хотите, чтобы оно было constexpr, вы можете воспользоваться трюком:

void f(Bar bar)
{
    auto lambda = [&](auto x_value)
    {
        constexpr bool x = x_value;
        // Here `x` is `constexpr`.
    };

    if (bar.x)
        lambda(std::true_type{});
    else
        lambda(std::false_type{});
}
...