Использование пустых структур в C ++ - PullRequest
1 голос
/ 14 марта 2020

В некотором коде, который я читал, я обнаружил использование пустой структуры, например, так:

struct input_iterator_tag { };
struct bidirectional_iterator_tag { };
struct random_access_iterator_tag { };

Так что в остальной части кода она использовалась как то, что они называют tag dispatching.

Мне было интересно, есть ли другое использование пустых структур.

из более старой записи Я видел, что:

три основные причины, по которым мы используем пустые структуры в C ++:

  • a базовый интерфейс
  • параметр шаблона
  • тип, помогающий разрешать перегрузки. (отправка тегов, если я не ошибаюсь)

Может кто-нибудь объяснить это, пожалуйста?

Ответы [ 2 ]

3 голосов
/ 14 марта 2020

тип, чтобы помочь разрешению перегрузки. (отправка тегов, если я не ошибаюсь)

Когда вы хотите использовать сложный шаблон специализации шаблона для какой-либо функции, вы не пытаетесь go напрямую использовать ее, а пишите:

template <typename T1, typename T2, other things maybe>
int foo(T1 param1, T2 param2 and so on)
{
    using tag = put your complex stuff here, which produces an empty struct
    detail::foo_impl(tag, std::forward<T1>(param1), std::forward<T2>(param2) and so on);
}

Теперь компилятору не нужно выбирать между конкурирующими вариантами специализации шаблона, поскольку с разными тегами вы получаете несовместимые функции.

базовый интерфейс

struct vehicle { };

namespace mixins {
struct named { std::string name; };
struct wheeled { int num_wheels; public; rev() { }; }

}  // namespace mixins

struct private_sedan : public vehicle, public wheeled, named {
   // I dunno, put some car stuff here
};

Создание базовой структуры полностью пустой, возможно, не так часто, но, безусловно, возможно, если вы часто используете миксины. И вы можете проверить наследование от vehicle (хотя я не уверен, что я это сделаю).

параметр шаблона

Не уверен, что это значит, но рискну предположить:

template <typename T>
struct foo { }

template <typename T, typename N>
struct foo<std::array<T, N>> {
    int value = 1;
}

Если вы теперь используете foo<T>::value в функции, она будет работать только в том случае, если T равно int с несколькими (?) Исключениями.

1 голос
/ 14 марта 2020

Я также пытался придумать примеры:

в качестве базового интерфейса

// collection of very abstract vehicles
#include <vector>

struct Vehicle {};
struct Car : Vehicle {
    int count_of_windows;
};
struct Bike : Vehicle {
    int size_of_wheels;
};

std::vector<Vehicle> v{Bike{}, Car{}};

в качестве параметра шаблона

// print same number in 3 different formats

#include <iostream>

struct dec {};
struct hex {};
struct octal {};

template<typename HOW = dec>
void print_me(int v);

template<>
void print_me<dec>(int v) {
    auto f = std::cout.flags();
    std::cout << std::dec << v << std::endl;
    std::cout.flags(f);
}

template<>
void print_me<hex>(int v) {
    auto f = std::cout.flags();
    std::cout << std::hex << v << std::endl;
    std::cout.flags( f );
}

template<>
void print_me<octal>(int v) {
    auto f = std::cout.flags();
    std::cout << std::oct << v << std::endl;
    std::cout.flags(f);
}

int main() {
  print_me(100);
  print_me<hex>(100);
  print_me<octal>(100);
}

тип для разрешения перегрузки

// add a "noexcept" qualifier to overloaded function
// the noexcept version typically uses different functions
// and a custom "abort" handler

#include <iostream>

struct disable_exceptions {};

void is_number_1() {
    int v;
    std::cin >> v;
    if (v != 1) {
        throw new std::runtime_error("AAAA");
    }
}

void is_number_1(disable_exceptions) noexcept {
    int v;
    // use C function - they don't throw
    if (std::scanf("%d", &v) != 1) {
        std::abort();
    }
    if (v != 1) {
        std::abort();
    }
}

int main() {
    is_number_1();
    is_number_1(disable_exceptions());
}

Пример "диспетчеризации тегов" можно найти в cppreference iterator_tags . Член iterator_category() итератора используется для выбора другой перегрузки. Таким образом, вы могли бы написать другой алгоритм, если, например, iterator - forward_iterator, где вы можете только go forward, или это двунаправленный_iterator, где ваш алгоритм может измениться, потому что вы можете вернуться назад.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...