2016-02-12 3 views
2

Я хочу переключить возможные значения двух целых чисел, или в другом случае два bools. Ради обсуждения, предположим, что я сделалоператор switch для std :: pair?

auto mypair = std::make_pair(foo, bar); 

Как можно достичь эквивалент

switch(mypair) { 
case make_pair(true, false): cout << "true and false"; break; 
case make_pair(false, true) cout << "false and true"; break; 
case default: cout << "something else"; 
} 

с C++ 11? (C++ 14/17 также актуально, если это помогает)?

+0

я думаю [это] (http://en.cppreference.com/w/cpp/language/switch) помог бы. См., В частности, то, что ожидается как условие * *, и как оно определяется * constant_expression * оператора * case *, прежде чем продолжить. Что вы ожидаете от своего фрагмента? – skypjack

ответ

2

Оператор switch C++ не обладает способностью сопоставления шаблонов многих других языков. Вам нужно будет сделать несколько иной подход.

Вот возможность я бросил вместе:

pair_switch(my_pair, 
    std::make_tuple(true, false, []{ std::cout << "true and false"; }), 
    std::make_tuple(false, true, []{ std::cout << "false and true"; })); 

Вы обеспечиваете std::pair<bool,bool> и множество случаев, как std::tuples, где первые два элемента совпадают пары вы передаете в и третий элемент является функция для вызова для этого случая.

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

template <typename... Ts> 
void pair_switch(std::pair<bool,bool> pair, Ts&&... ts) { 
    //A table for the cases 
    std::array<std::function<void()>, 4> table {}; 

    //Fill in the cases 
    (void)std::initializer_list<int> { 
     (table[std::get<0>(ts)*2 + std::get<1>(ts)] = std::get<2>(ts), 0)... 
    }; 

    //Get the function to call out of the table 
    auto& func = table[pair.first*2 + pair.second]; 

    //If there is a function there, call it 
    if (func) { 
     func(); 
    //Otherwise, throw an exception 
    } else { 
     throw std::runtime_error("No such case"); 
    } 
} 

Live Demo

+0

ОК, вы заслуживаете +1 в любом случае, по крайней мере, за то, как вы использовали 'initializer_list', чтобы заполнить массив. Вводная. Этот оператор просто разворачивает пакет параметров в массив (таким образом, отбрасывание списка имеет смысл), или есть другая цель, которую я не вижу? Любите ', 0' часть, действительно, никогда не думали что-то подобное, чтобы развернуть пакет, действительно умный !! – skypjack

+0

Он использует тот факт, что вы можете распаковать пакеты параметров в контексте 'initializer_list', а затем просто заполняет массив как побочный эффект и отбрасывает' initializer_list'. Эта уродство будет исправлена, если на языке будут слагаемые. – TartanLlama

+0

ОК, он работает, как я понял, хорошо. Действительно интересная и хорошая идея. Складные выражения означают 202y, я не прав? – skypjack

0

Вы можете переключиться только на интегральном типе, но если вы можете разработать функцию, чтобы сопоставить пару (или какой-либо сложный тип) для целочисленного типа, вы можете объявить его как constexpr (C++ 11), чтобы указать, что он может быть разрешен во время компиляции. Тогда это приемлемо как выражение случая.

Простой пример:

enum Action { peel, eat, juice }; 
enum Fruit { apple, orange, banana }; 

constexpr unsigned int switch_pair(Action a, Fruit f) { 
    return (a << 16) + f; 
} 

Затем определите переключатель так:

switch(switch_pair(mypair.first,mypair.second)) 
{ 
    case switch_pair(peel,apple): std::cout << "Peeling an apple" << std::endl; break; 
    case switch_pair(eat,apple): std::cout << "Eating an apple" << std::endl; break; 
    case switch_pair(juice,apple): std::cout << "Juicing an apple" << std::endl; break; 
    default: 
     throw std::runtime_error("We only have apples!"); 
} 
Смежные вопросы