是否可以代理任何功能

时间:2017-01-27 23:11:49

标签: c++

我使用一个带有不同参数的函数的(C)库,但在出现错误时总是返回大于零的int:

int functionA(int param1, char param2); /* return an error code on failure, 0 otherwise */
int functionB(LIB_BOOLEAN param1);      /* return an error code on failure, 0 otherwise */
// ...

我想把它们全部变为异常准备好了:

if (functionA(param1, param2) > 0)
{ throw std::runtime_error("Method failed"); }

是否有可能为所有方法编写模板一次?

编辑: 我们的想法是每次使用时都避免检查每个函数的结果。

5 个答案:

答案 0 :(得分:6)

你的意思是这样吗?

template<typename F, typename... Args>
auto my_invoke(F &&f, Args&&... args) {
    if(std::forward<F>(f)(std::forward<Args>(args)...)) {
        throw std::runtime_error("Method failed");
    }
}

您可以将其称为;

my_invoke(functionA, 0, 'c');

答案 1 :(得分:2)

以下是使用C ++ 17的新auto模板参数的基于模板的解决方案:

template <auto &> struct CallerImpl;

template <typename ...Args, int (&F)(Args ...)>
struct CallerImpl<F>
{
    static int CallOrThrow(Args ... args)
    {
        if (int n = F(args...); n > 0)
            throw std::runtime_error("Method failed");
        else
            return n;
    }
};

template <auto & F, typename ... Brgs>
int CallOrThrow(Brgs ... brgs)
{
    return CallerImpl<F>::CallOrThrow(brgs...);
}

用法示例:

int foo(double, char)
{
    std::cout << "Foo called\n";
    return 8;
}

CallOrThrow<foo>(1.5, 'x');

答案 2 :(得分:2)

我知道我会因此而被投票,但老实说,我认为这是一个可以有效使用预处理器的案例:

#define CHECK( fn ) \
    { \
        if( fn > 0 ) { \
            throw "problem"; \
        } \
    } 


int f(int x) {
    return x - 1;
}


int main() {
    CHECK( f(42) );
}

很明显,它很简单,很简单,可以使用__LINE____FILE__和其他预定义的宏,而这些宏不能用于模板。

答案 3 :(得分:1)

#!/bin/bash
i=1
c=1
options=()
while [ $c -gt 0 ]
do
    v=$(phpbrew list | sed -n "${i}p")
    if [ -z "$v" ]; then
        c=0
    elif [ -n "$v" ]; then
        options+=("$v")
    fi
    i=$[$i+1]
done

count=0
printf "\n"
echo 'Available versions:'
for i in "${options[@]}"
do
 echo "$i $[$count+1]"
 count=$[$count+1]
done

printf "\n"
echo 'Which version should be enabled?'
read selected

chosen="${options[$selected - 1]}"
chosen="$(echo -e "${chosen}" | tr -d '[:space:]')"
chosen="$(echo -e "${chosen}" | sed 's/\*//g')"
chosen="$(echo -e "${chosen}" | sed 's/php-//g')"
echo -e "php-${chosen} to be enabled."

source $HOME/.phpbrew/bashrc
phpbrew switch php-${chosen}

if [[ $chosen =~ ^5 ]]; then
    sudo a2dismod php7
    sudo a2enmod php5
    sudo service apache2 reload
elif [[ $chosen =~ ^7 ]]; then
    sudo a2dismod php5
    sudo a2enmod php7
    sudo service apache2 reload
else echo 'This script only works on php 5 and 7';
fi

未经测试,但这样的事情应该有效。

希望它有所帮助!

答案 4 :(得分:1)

这是一种不需要更改呼叫站点的方法。假设这些C函数对返回代码都有相同的约定,您可以编写一个将返回代码转换为异常的包装器。

inline void checked(const char *name, int result) {
    if (result > 0)
        throw std::runtime_error(name);
}

然后为每个函数引入预处理器定义。

#define functionA(...) checked("functionA", functionA(__VA_ARGS__))

这是有效的,因为functionA不会在functionA宏的定义中展开。从C ++ 11开始,可变参数宏是标准的。