【问题标题】:Type of member functions arguments成员函数参数的类型
【发布时间】:2017-12-20 12:46:48
【问题描述】:

使用 C++11 我试图从函数名称中获取函数参数的类型,因为函数签名是明确的。最终,我试图检查一个参数是否正是我想要的类型我调用一个函数之前。

到目前为止,由于这个解决方案,我可以使用非成员函数来做到这一点: Unpacking arguments of a functional parameter to a C++ template class

我稍微编辑了它以获得以下类:

template<typename T>
struct FunctionSignatureParser; // unimplemented primary template
template<typename Result, typename...Args>
struct FunctionSignatureParser<Result(Args...)>
{
    using return_type = Result;
    using args_tuple = std::tuple<Args...>;
    template <size_t i> struct arg
    {
        typedef typename std::tuple_element<i, args_tuple>::type type;
    };
};

例如,我可以在编译时检查函数的类型:

short square(char x) { // 8-bit integer as input, 16-bit integer as output
    return short(x)*short(x);
}
int main() {
        char answer = 42;
        static_assert(std::is_same<char, FunctionSignatureParser<decltype(square)>::arg<0>::type>::value, "Function 'square' does not use an argument of type 'char'");
        static_assert(std::is_same<short, FunctionSignatureParser<decltype(square)>::return_type>::value, "Function 'square' does not return a value of type 'short'");
        short sqrAnswer = square(answer);
        std::cout << "The square of " << +answer << " is " << +sqrAnswer << std::endl;
        return 0;
}

>> Online code with gcc

但是当我想检查成员函数的类型时,有些编译器对此并不满意:

struct Temperature
{
    double degrees;
    Temperature add(double value);
};
int main() {
    Temperature t{16};
    double increment{8};
    static_assert(std::is_same<double, FunctionSignatureParser<decltype(t.add)>::arg<0>::type>::value, "Method 'Temperature::add' does not use an argument of type 'double'");
    std::cout << t.degrees << u8" \u00b0C + " << increment << " == " << t.add(increment).degrees << u8" \u00b0C" << std::endl;
    return 0;
}

这是 gcc 6.3 的内容:

错误:非静态成员函数'Temperature Temperature::add(double)'的使用无效

>> Online code with gcc

clang 4.0 的内容如下:

错误:必须调用非静态成员函数的引用

>> Online code with clang

我尝试了这些选项,但无济于事:

decltype(Temperature::add)
decltype(std::declval<Temperature>().add)

decltype 中的非静态成员函数有什么问题?由于 decltype 中的表达式不被计算,static 限定符应该无关紧要,对吧?

郑重声明,MSVC12 在这种情况下成功了。不过,我无法判断 Microsoft 编译器是对还是错。 (请不要让这个线程成为编译器之战)

另外,如果您有不涉及初始方法的参数检查解决方案,我也愿意接受。

【问题讨论】:

  • 我不会将 MSVC12 用作标准一致性的典范。 15.5编译器(VS2017.5)能再测试一下吗?
  • @Mgetz 我同意 MSVC12 并不理想,但目前这是我可以获得的最新版本,因此我无法使用 15.5 进行测试。

标签: c++ c++11 gcc decltype member-functions


【解决方案1】:

您需要对成员函数进行另一种模板特化,如下所示:

template<typename ClassType, typename Result, typename...Args>
struct FunctionSignatureParser<Result(ClassType::*)(Args...)>
{
    using return_type = Result;
    using args_tuple = std::tuple<Args...>;
    template <size_t i> struct arg
    {
        typedef typename std::tuple_element<i, args_tuple>::type type;
    };
};

而且可以这样使用:

    static_assert(std::is_same<double, FunctionSignatureParser<decltype(&Temperature::add)>::arg<0>::type>::value, "Method 'Temperature::add' does not use an argument of type 'double'");

这适用于 gcc 7.2,尚未测试其他编译器

【讨论】:

  • 这就像 gcc 6.3、clang 4.0 和 MSVC12 的魅力。非常感谢,@dvk。我仍然不明白为什么 clang 和 gcc 拒绝非静态成员函数,但这是次要的,因为该解决方案完全解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 2019-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多