类型和非类型模板专业化

时间:2017-02-27 14:32:35

标签: c++ metaprogramming template-meta-programming c++17

我想为类型和函数编写MP预测器。似乎有些事情是非法的:

#include <iostream>

template <class R>
struct X { 
    static constexpr int value = 0;
};

// Specialization for type
template <>
struct X<int(int)> {
    static constexpr int value = 1;
};

// ERROR: Redefinition with diffrent kind
template <int (*F)(int)>
struct X { 
    static constexpr int value = 2;
};

int fun(int);

int main(int, char* []) 
{
    std::cout << "X<int>: " << X<int>::value << '\n';
    std::cout << "X<int(int)>: " << X<int(int)>::value << '\n';
    std::cout << "X<decltype(fun)>: " << X<decltype(fun)>::value << '\n';
    std::cout << "X<fun>: " << X<fun>::value << '\n';
    return 0;
}

是否有可能实现这样的目标?

更多细节: 为什么?

  1. 学习元编程
  2. 编写一个通用预测器,可以说是否使用给定参数调用函数/对象实例(类似于C ++ 17中的is_callable)

2 个答案:

答案 0 :(得分:2)

  

是否有可能实现这样的目标?

您有效地询问的是您是否可以重载类模板。你不能。

但是,你当然可以重载函数模板 - 你可以有一个函数模板,它接受一个非推导的模板类型参数,专门化它,然后有另一个函数模板,它接受一个非推导模板非类型参数:< / p>

#include <iostream>

template <class R> constexpr int X() { return 0; }    

// specialization for type
template <> constexpr int X<int(int)>() { return 1; }

// Redefinition with different kind
template <int (*F)(int)>
constexpr int X() { return 2; }

int fun(int);

int main(int, char* []) 
{
    std::cout << "X<int>: " << X<int>() << std::endl;
    std::cout << "X<int(int)>: " << X<int(int)>() << std::endl;
    std::cout << "X<decltype(fun)>: " << X<decltype(fun)>() << std::endl;
    std::cout << "X<fun>: " << X<fun>() << std::endl;
    return 0;
}

根据需要打印0,1,1和2。

答案 1 :(得分:0)

我认为这是不可能的。 template参数只能是类型或值。在声明中:

template <class R>
struct X {
    static constexpr int value = 0;
};

指定X以将类型作为参数。

// ERROR: Redefinition with diffrent kind
template <int (*F)(int)>
struct X {
    static constexpr int value = 2;
};

您想要专门化X来获取值(函数指针)。这确实与你首先声明了X.因此你得到了重新定义错误。

如果您想以更一般的方式实现预测器,则必须使用SFINAE模式。我在过去写了类似的东西,但放弃了它,因为它使用起来太笨拙而容易出错。我不太记得,但我想我发现了一些不成功的案例。出于教育目的,我在这里发布代码:

#include <type_traits>
#include <iostream>

namespace Detail {

template <
    class Function,
    class Result,
    class Enable,
    class... Args
>
struct isFunctionImpl {
    static constexpr bool value = false;
};

template <
    class Function,
    class Result,
    class... Arg
>
struct isFunctionImpl <
    Function,
    Result,
    typename std::enable_if<
        std::is_same<
            Result,
            decltype(std::declval<Function>()(*reinterpret_cast<Arg*>(0)...))
        >::value
    >::type,
    Arg...
> {
    static constexpr bool value = true;
};

} // End of namespace Detail

template <
    class Function,
    class Result,
    class... Args
>
struct isFunction {
    static constexpr bool value = Detail::isFunctionImpl<Function, Result, void, Args...>::value;
};

int foo(int bar) {
    return 0;
}

int main() {
    std::cout << "Is function " << isFunction<decltype(foo), int, int>::value << std::endl;
    std::cout << "Is function " << isFunction<decltype(foo), int, std::string>::value << std::endl;
}