2012-11-04 136 views
4

这里是我想要做的情况为例(这是一个“测试”的情况下只是为了说明问题):传递一个整数或类型作为模板参数?

#include <iostream> 
#include <type_traits> 
#include <ratio> 

template<int Int, typename Type> 
constexpr Type f(const Type x) 
{ 
    return Int*x; 
} 

template<class Ratio, typename Type, 
     class = typename std::enable_if<Ratio::den != 0>::type> 
constexpr Type f(const Type x) 
{ 
    return (x*Ratio::num)/Ratio::den; 
} 

template</*An int OR a type*/ Something, typename Type> 
constexpr Type g(const Type x) 
{ 
    return f<Something, Type>(x); 
} 

int main() 
{ 
    std::cout<<f<1>(42.)<<std::endl; 
    std::cout<<f<std::kilo>(42.)<<std::endl; 
} 

正如你所看到的,也有f()函数的两个版本:第一个采用int作为模板参数,第二个采用std::ratio。问题如下:

我想“包装”这个功能通过g()可以采取intstd::ratio作为第一个模板参数和调用f()好的版本。

如何做到这一点,而不写两个g()功能?换句话说,我必须写什么来代替/*An int OR a type*/

回答

2

这是我会怎么做,但我已经略有改变你的接口:

#include <iostream> 
#include <type_traits> 
#include <ratio> 

template <typename Type> 
constexpr 
Type 
f(int Int, Type x) 
{ 
    return Int*x; 
} 

template <std::intmax_t N, std::intmax_t D, typename Type> 
constexpr 
Type 
f(std::ratio<N, D> r, Type x) 
{ 
    // Note use of r.num and r.den instead of N and D leads to 
    // less probability of overflow. For example if N == 8 
    // and D == 12, then r.num == 2 and r.den == 3 because 
    // ratio reduces the fraction to lowest terms. 
    return x*r.num/r.den; 
} 

template <class T, class U> 
constexpr 
typename std::remove_reference<U>::type 
g(T&& t, U&& u) 
{ 
    return f(static_cast<T&&>(t), static_cast<U&&>(u)); 
} 

int main() 
{ 
    constexpr auto h = g(1, 42.); 
    constexpr auto i = g(std::kilo(), 42.); 
    std::cout<< h << std::endl; 
    std::cout<< i << std::endl; 
} 

42 
42000 

注:

  1. 我已经采取constexpr编译期通的优势时间常数通过模板参数(这就是constexpr)。

  2. g现在只是一个完美的货运代理。但是我无法使用std::forward,因为它没有用constexpr(可以说是C++ 11中的缺陷)标记。所以我放弃使用static_cast<T&&>来代替。完美的转发在这里有点矫枉过正。但彻底熟悉这是一个很好的习惯用法。

+1

在您的编辑:为什么不命名您的'std :: ratio'参数并使用'r.num'和'r.den'? :) – Xeo

+0

@Xeo:好的建议,谢谢!完成。 –

+1

也许也解释了为什么你特别使用成员而不是'N'和'D',而不是只在编辑历史中使用它。 – Xeo

1

如何做到这一点,而不写两个g()函数?

你不知道。 C++没有办法使用某种类型的类型或值,除非通过重载。

0

不可能有模板参数同时包含类型和非类型值。

解决方案1:

重载函数。

解决方案2:

可以存储类型的值。例如:

template<int n> 
struct store_int 
{ 
    static const int num = n; 
    static const int den = 1; 
}; 

template<class Ratio, typename Type, 
     class = typename std::enable_if<Ratio::den != 0>::type> 
constexpr Type f(const Type x) 
{ 
    return (x*Ratio::num)/Ratio::den; 
} 

template<typename Something, typename Type> 
constexpr Type g(const Type x) 
{ 
    return f<Something, Type>(x); 
} 

但有了这个解决方案,您将需要指定的,而不是g<42>(...)

g<store_int<42> >(...)如果函数是小,我建议你使用过载。

+0

解决方案2可以使用'std :: ratio'。 – kennytm

+0

我同意你的例子。但有些情况下它可能有用(例如:不是'std :: ratio',而是另一个需要大量参数的模板)。 – Synxis

相关问题