2015-03-06 2 views
3

Я пишу класс C++, который взаимодействует с библиотекой. Библиотека имеет кучу функций, которые выглядят следующим образом:Аргументы функции «Преобразование»

Library.h

int FunctionA(int deviceNumber, ...); 
int FunctionB(int deviceNumber, ...); 
int FunctionC(int deviceNumber, ...); 
int FunctionD(int deviceNumber, ...); 
int FunctionE(int deviceNumber, ...); 

Каждый экземпляр моего C++ класс имеет ассоциированный deviceNumber, который никогда не меняется, так что я deviceNumber хранится как член переменной, и каждый раз, когда я вызываю библиотечную функцию, я передаю член в качестве первого аргумента функции.

Это прекрасно, и нет никакой реальной причины для меня изменить то, как оно есть. Но из любопытства мне было интересно, есть ли у C++ какой-либо механизм для «преобразования» аргументов, который позволил бы мне избежать передачи одного и того же аргумента в каждом вызове. Очевидный способ добиться этого - перегрузить все. Скажем, мой класс называется Foo:

foo.cpp

int Foo::FunctionA(...) { 
    // deviceNumber_ is a const member 
    return ::FunctionA(deviceNumber_, ...); 
} 

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

Есть ли какой-либо общий способ обеспечить перегрузку без фактической перегрузки функций? Есть ли механизм в C++ для «расширения» аргумента в несколько аргументов? Я воображая это будет выглядеть так:

// These two calls are equivalent 
FunctionA(deviceNumber, ...); 
FunctionA(Magic(...)); 
// Magic() expands the arguments, adding deviceNumber 

Даже если решение гораздо уродливее и менее читаемым, чем оставить все в покое, мне очень интересно, если это возможно. После поиска вокруг, вариативные шаблоны кажутся ближайшим совпадением, но я не могу обернуть вокруг себя то, как они могут быть использованы для этого.

+0

Как насчет сделать DeviceNumber к частному стоимость. и сделать базовый класс. , то унаследованная функция-член не нужно использовать devicenumber. –

+2

Будет ли работать макрос? '#define MAGIC (...) deviceNumber_, __VA_ARGS__' –

+0

Macro также является хорошим выбором для очень небольшой разницы –

ответ

4

Вы могли бы быть счастливы с общей функцией реле:

Live On Coliru

#include <iostream> 

int foo1(int device_number, const char*) { std::cout << __PRETTY_FUNCTION__ << "\n"; return device_number*42; } 
double foo2(int device_number)    { std::cout << __PRETTY_FUNCTION__ << "\n"; return device_number*3.14159; } 

struct facade { 
    facade(int dn) : device_number(dn) {} 

    template <typename F, typename... A> 
     auto call(F&& f, A&&... args) const { 
      return std::forward<F>(f)(device_number, std::forward<A>(args)...); 
     } 

    private: 
    int device_number; 
}; 

int main() { 

    facade dev(2); 

    std::cout << dev.call(foo1, "yes ma'am") << "\n"; 
    std::cout << dev.call(foo2) << "\n"; 

} 
+0

И [если Бьярне получает свой путь] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4174.pdf), мы можем записать последнее как 'foo1 (dev, «да, мэм»), и он будет выглядеть единообразным и удобным :-) Или мы принимаем [N4165] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/ n4165.pdf), и OP может сказать 'deviceNumber.functionA (...)' ... Ум боится. –

+0

Oh .. хорошее использование шаблона ссылка. спасибо, что показал этот путь. но очень сложный и сложный. ^^ –

0

Я установил псевдокод, для структуры типа C++.

Прототип класса может иметь следующие формы.

class Foo { 
    private private_member_of_deviceNumber; 
    .... 
    int FunctionA(...); 
    .... 
} 

Конструктор класса Foo присваивает номер устройства переменной частному члену.

class Foo::Foo(int deviceNumber) { 
    int private_member_of_deviceNumber = deviceNumber; 
} 

Foo Класс участник FunctionA (...) понравится эта форма.

int Foo::FunctionA(...) { 
    return ::FunctionA(private_member_of_deviceNumber , ...); 
} 

Как насчет этого способа?

+0

Это то, что я пытался получить с помощью моего примера «Foo.cpp». Это работает, но если библиотека имеет кучу функций с похожими прототипами, я бы в конечном итоге определил тонну методов для их перегрузки. Мне было интересно, есть ли способ сделать это с фиксированными накладными расходами, независимо от того, сколько там функций библиотеки. –

+0

Базовая форма @Matt такова, и вам нужно удалить ту же самую трудоемкую копию задания и вставить кучу библиотечного кода. Затем вы используете макрос и шаблон, другой ответ отправил его. Хорошая работа! –

1

я бы, вероятно, выбрать Марка в файле CPP, как простое решение (строго в файле CPP, хотя)

шаблоны VARIADIC могли бы помочь здесь. Однако похоже, что вы делаете что-то встроенное, и это может быть проблемой.

Кроме того, я не уверен, что вы имеете в виду, что каждая функция A перегружена или FunctionA относится к одной функции.

Во всяком случае, мой шаблон решение поможет, если есть несколько FunctionAs

template<typename... Args> 
int Foo::FunctionA(Args&& ...args) { 
    return ::FunctionA(deviceNumber_, std::forward<Args>(args)...); 
} 
+0

Шаблоны Variadic не являются проблемой. Библиотека управляет встроенным устройством, но я вызываю библиотеку из настольной программы с полной поддержкой C++ 11. Кроме того, FunctionA не перегружен. Я упомянул о моем решении обернуть глобальный вызов FunctionA эквивалентным методом как «перегрузку», но я не уверен, что это правильный способ его фразы. –

Смежные вопросы