Consider this illegal code:
template <int... Is>
struct Object {
void foo() const;
};
template <int... Js>
void Object<0, Js...>::foo() {/*Do whatever*/}
We want to specialize foo() when the first template parameter is 0, and let's say we want to specialize foo() as well if the second parameter is 3, and the third int is 1. So the solution I found (not sure if its the best approach) is the following:
#include <iostream>
template <int...> struct Foo;
template <int... Is>
struct Object {
int ID; // This member is just to illustrate the case when 'this' is needed in foo().
friend struct Foo<Is...>;
void foo() const {Foo<Is...>::execute(this);} // Pass 'this' in case it is needed.
};
template <int... Is>
struct Foo<0, Is...> {
static void execute (const Object<0, Is...>* object) {std::cout << "First int = 0, ID = " << object->ID << ".\n";}
};
template <int N, int... Is>
struct Foo<N, 3, Is...> {
static void execute (const Object<N, 3, Is...>* object) {std::cout << "Second int = 3, ID = " << object->ID << ".\n";}
};
template <int M, int N, int... Is>
struct Foo<M, N, 1, Is...> {
static void execute (const Object<M, N, 1, Is...>* object) {std::cout << "Third int = 1, ID = " << object->ID << ".\n";}
};
int main() {
Object<0,5,8,2>{4}.foo();
Object<4,3,2,5,3>{2}.foo();
Object<4,2,1>{0}.foo();
}
First of all, is this solution any good? Next, the problem now arises if we try Object<0,3,1,4>{8}.foo(); because the spec was not complete. So let's say that the earliest matched specialized int will always take precedence. So in this case Object<0,3,1,4>{8}.foo(); should run the first specialization because of the 0, while Object<9,3,1,4>{8}.foo(); shall run the second specialization because of the 3, and so forth. How to enforce that rule?
I suggest just using if statements. The compiler will probably optimize them away anyway (assuming you have optimization enabled).
In other words, just do something like this:
template <int... Js>
void Object::foo() {
std::array<int, sizeof...(Js)> args = {Js...}; // I _think_ this is the correct syntax to dump the parameter pack into an std::array.
if(args.size() > 0 && args[0] == 0) {
// First argument is 0, do whatever.
} else {
// It's not 0, do your other thing.
}
}
You'll get pretty much the same effect, and your code will be quite a bit clearer.
A comment and a hint.
The approach for me is OK. Since we do not have partial template specialization for functions that's all we have.
Then regarding Object<0,3,1,4>{8}.foo() this gives ambiguous partial specializations (on Clang 3.6). To solver this problem I ended up adding another partial specialization
template <int... Is>
struct Foo<0, 3, Is...> {
static void execute (const Object<0, 3, Is...>* object) {std::cout << "First int = 0, second = 3, ID = " << object->ID << ".\n";}
};
Another possibility is mess with std::integer_sequence. I have to give up now, the following is not a solution, just an appetizer...
#include <utility>
#include <iostream>
template <class S1, class S2>
struct seq_lt
{
enum {value = 0} ;
} ;
template <int I1, int ...S1, int I2, int ...S2>
struct seq_lt<std::integer_sequence<int, I1, S1...>,
std::integer_sequence<int, I2, S2...>>
{
enum {value = (I1 < I2 ? 1 : 0)} ;
} ;
int main(int argc, char *argv[])
{
std::integer_sequence<int, 1, 2, 3> seq1 ;
std::integer_sequence<int, 2, 3> seq2 ;
std::cout << "seq_lt " << seq_lt<decltype(seq1), decltype(seq2)>::value << std::endl ;
std::cout << "seq_lt " << seq_lt<decltype(seq2), decltype(seq1)>::value << std::endl ;
}
This solution was inspired by Marom's second suggestion, and also inspired partly by celticminstrel's solution too.
#include <iostream>
#include <type_traits>
template <std::size_t, typename T, T...> struct NthValue;
template <typename T, T First, T... Rest>
struct NthValue<0, T, First, Rest...> : std::integral_constant<T, First> {};
template <std::size_t N, typename T, T First, T... Rest>
struct NthValue<N, T, First, Rest...> : NthValue<N - 1, T, Rest...> {};
template <int... Is>
struct Object {
void foo() const {fooHelper (typename Map<Is...>::type{});}
private:
template <int...> struct Map;
template <int, int> struct MappedType {};
struct Default {};
void fooHelper (const MappedType<0,0>&) const {std::cout << "First int = 0.\n";}
void fooHelper (const MappedType<1,3>&) const {std::cout << "Second int = 3.\n";}
void fooHelper (const MappedType<2,1>&) const {std::cout << "Third int = 1.\n";}
void fooHelper (const Default&) const {std::cout << "Default case.\n";}
};
template <int... Ns>
template <int... Is>
struct Object<Ns...>::Map {
using type = typename std::conditional<NthValue<0, int, Is...>::value == 0,
MappedType<0,0>,
typename std::conditional<NthValue<1, int, Is...>::value == 3,
MappedType<1,3>,
typename std::conditional<NthValue<2, int, Is...>::value == 1,
MappedType<2,1>,
Default
>::type
>::type
>::type;
};
int main() {
Object<0,5,8,2>().foo(); // First int = 0.
Object<4,3,2,5,3>().foo(); // Second int = 3.
Object<4,2,1>().foo(); // Third int = 1.
Object<0,3,1,4>().foo(); // First int = 0.
Object<9,3,1,4>().foo(); // Second int = 3.
Object<9,9,9>().foo(); // Default case.
}
There is also no run-time overhead.
Related
I was given a template meta-programming challenge of using only C++11 standard to print out a series of integers in powers of 2 which I have successfully done:
#include <iostream>
template <size_t... Ns>
struct index_sequence
{
static void print()
{
const size_t numbers[] = {Ns...};
for (const auto& number : numbers)
{
std::cout << number << ", ";
}
std::cout << std::endl;
}
};
//#include <cmath>
template <size_t Counter, size_t... Rest>
struct make_sequence_impl
{
using type = typename make_sequence_impl<
Counter - 1,
static_cast<size_t>(1) << Counter, Rest...>::type;
};
template <size_t... Rest>
struct make_sequence_impl<0, Rest...>
{
using type = index_sequence<static_cast<size_t>(1) << 0, Rest...>;
};
template <size_t T>
using make_sequence = typename make_sequence_impl<T>::type;
int main()
{
make_sequence<N>::print();
}
Assuming N is 5, it would print 1, 2, 4, 8, 16.
However, I was subsequently challenged to do the same thing, except that this time I have to print them in reverse order (i.e. 16, 8, 4, 2, 1 for N = 5). I am totally stumped but I am very sure it involved only a slight change to the code which I can't figure out how.
Any help would be appreciated. Got into template meta-programming a few days ago.
Not sure if it is the minimal change, but instead of "push_front" the sequence, you might "push_back".
template <size_t Counter, size_t... Rest>
struct make_sequence_impl
{
using type = typename make_sequence_impl<
Counter - 1,
Rest...,
static_cast<size_t>(1) << Counter>::type;
};
template <size_t... Rest>
struct make_sequence_impl<0, Rest...>
{
using type = index_sequence<Rest..., static_cast<size_t>(1) << 0>;
};
Demo
On my side, I would mimic std::make_index_sequence to have 0, 1, 2, .., N-1 and then use it directly:
emplate <size_t Counter, size_t... Rest>
struct make_sequence_impl
{
using type = typename make_sequence_impl<
Counter - 1,
Counter,
Rest...>::type;
};
template <size_t... Rest>
struct make_sequence_impl<0, Rest...>
{
using type = index_sequence<0, Rest...>;
};
and then
template <std::size_t ... Is>
void print( index_sequence<Is...> )
{
for (const auto& number : {Is...})
{
std::cout << number << ", ";
}
std::cout << std::endl;
}
template <std::size_t ... Is>
void print_pow2( index_sequence<Is...> )
{
print(index_sequence<(1u << Is)...>{});
}
template <std::size_t ... Is>
void print_pow2_inv( index_sequence<Is...> )
{
print(index_sequence<(1u << (sizeof...(Is) - 1 - Is))...>{});
}
Demo
Is there a way to establish at compile time if a certain function template was specialized?
For example, assume the following function template:
template<size_t N>
void foo();
I want to test if foo<42> was specialized. Note that the declaration above doesn't contain any default implementation.
I tried SFINAE but couldn't find a condition on the function that the compiler cannot deduce from its declaration.
Is there a way to establish in compile time if a certain template function was specialized?
With a function... I don't think so.
But if you create a functor, you can add a static const member (is_specialized, in the following example) that can give you this information
#include <iostream>
template <std::size_t N>
struct foo
{
static constexpr bool is_specialized { false };
void operator() () const
{ std::cout << "- generic (" << N << ") foo struct" << std::endl; }
};
template <>
struct foo<42U>
{
static constexpr bool is_specialized { true };
void operator() () const
{ std::cout << "- specialized (42) foo struct" << std::endl; }
};
int main()
{
foo<17U>()(); // print - generic (17) foo struct
foo<42U>()(); // print - specialized (42) foo struct
std::cout << foo<17U>::is_specialized << std::endl; // print 0
std::cout << foo<42U>::is_specialized << std::endl; // print 1
}
--- EDIT ---
Following the suggestion from Quentin (thanks again!) I've developed another functor-based solution that use something, to detect if the functor is generic or specialize, that is added only in the generic functor. In this case, a type instead a bool constant.
template <std::size_t N>
struct foo
{
// im_not_specialized is added only in the generic version!
using im_not_specialized = void;
void operator () () const
{ std::cout << "- generic (" << N << ") foo struct" << std::endl; }
};
template <>
struct foo<42U>
{
void operator () () const
{ std::cout << "- specialized (42) foo struct" << std::endl; }
};
This type can be used via SFINAE and I propose an example based on a constexpr isSpecialized() template function (with an helper function)
template <typename F>
constexpr bool isSpecializedHelper
(int, typename F::im_not_specialized const * = nullptr)
{ return false; }
template <typename F>
constexpr bool isSpecializedHelper (long)
{ return true; }
template <typename F>
constexpr bool isSpecialized ()
{ return isSpecializedHelper<F>(0); }
This require a little more work but isSpecialized() can be reused with different functors (im_not_specialized type based)
The following is a full working example
#include <iostream>
template <std::size_t N>
struct foo
{
// im_not_specialized is added only in the generic version!
using im_not_specialized = void;
void operator () () const
{ std::cout << "- generic (" << N << ") foo struct" << std::endl; }
};
template <>
struct foo<42U>
{
void operator () () const
{ std::cout << "- specialized (42) foo struct" << std::endl; }
};
template <typename F>
constexpr bool isSpecializedHelper
(int, typename F::im_not_specialized const * = nullptr)
{ return false; }
template <typename F>
constexpr bool isSpecializedHelper (long)
{ return true; }
template <typename F>
constexpr bool isSpecialized ()
{ return isSpecializedHelper<F>(0); }
int main()
{
foo<17U>()(); // print - generic (17) foo struct
foo<42U>()(); // print - specialized (42) foo struct
constexpr auto isSp17 = isSpecialized<foo<17U>>();
constexpr auto isSp42 = isSpecialized<foo<42U>>();
std::cout << isSp17 << std::endl; // print 0
std::cout << isSp42 << std::endl; // print 1
}
If you mark the base function as deleted (= delete), you can detect if it has been specialized using SFINAE (assuming the specialization itself is not deleted)
An expression like decltype(foo<N>()) will result in a substitution failure if foo<N> is marked as deleted. If you provide a specialization that is not deleted on the other hand the expression will not result in an error.
Using this you can create a simple trait class to check if foo has been specialized for a specific set of template parameters:
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo<N>(), void())> : std::true_type {};
1. Basic examples
C++11: godbolt
#include <type_traits>
template<std::size_t N>
void foo() = delete;
template<>
void foo<1>() { }
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo<N>(), void())> : std::true_type {};
int main()
{
static_assert(!is_foo_specialized<0>::value, ""); // foo<0> is not specialized
static_assert(is_foo_specialized<1>::value, ""); // foo<1> IS specialized
}
With C++20 you could also use a concept for this, e.g.: godbolt
#include <type_traits>
template<std::size_t N>
void foo() = delete;
template<>
void foo<1>() { }
template<std::size_t N>
concept is_foo_specialized = requires { foo<N>(); };
int main()
{
static_assert(!is_foo_specialized<0>); // foo<0> is not specialized
static_assert(is_foo_specialized<1>); // foo<1> IS specialized
}
2. Providing a default implementation
Due to the function being = delete'd it can't have a default implementation.
If you do require a default implementation for the function, you could use 2 functions instead:
one that is = delete'd (so SFINAE can detect it)
and another one that implements the default behaviour and forwards to the other if a specialization exists
C++11: godbolt
#include <type_traits>
#include <iostream>
template<std::size_t N>
void foo_specialized() = delete;
template<>
void foo_specialized<1>() { std::cout << "CUSTOMIZED!" << std::endl; }
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo_specialized<N>(), void())> : std::true_type {};
template<std::size_t N>
typename std::enable_if<!is_foo_specialized<N>::value>::type foo() {
std::cout << "DEFAULT!" << std::endl;
}
template<std::size_t N>
typename std::enable_if<is_foo_specialized<N>::value>::type foo() {
foo_specialized<N>();
}
int main()
{
foo<0>(); // -> DEFAULT!
foo<1>(); // -> CUSTOMIZED!
}
Or with C++20: godbolt
#include <type_traits>
#include <iostream>
template<std::size_t N>
void foo_specialize() = delete;
template<>
void foo_specialize<1>() { std::cout << "CUSTOMIZED!" << std::endl; }
template<std::size_t N>
concept is_foo_specialized = requires { foo_specialize<N>(); };
template<std::size_t N> requires (!is_foo_specialized<N>)
void foo() {
std::cout << "DEFAULT!" << std::endl;
}
template<std::size_t N> requires (is_foo_specialized<N>)
void foo() {
foo_specialize<N>();
}
int main()
{
foo<0>(); // -> DEFAULT!
foo<1>(); // -> CUSTOMIZED!
}
3. Compile-time shenanigans
This can of course also be used to iterate the specializations (within a certain limit) - or like you asked in the comments to find the nearest specialization of the function.
nearest_foo_specialized in this example will iterate over a range of values for N and check if a specialization of foo exists for this value.
N is the value where we want to start the search
SearchRange determines how many specializations will be checked (both up and down) from the provided N value (in this example we check for N's +/- 10)
CurrentDistance keeps track how far we've already searched from our starting N value, so we don't exceed the specified SearchRange
The last template parameter is used for SFINAE
e.g.:
nearest_foo_specialized<100, 10> would check for specializations of foo between N = 90 and N = 110, returning the one that is closer to 100 (prefering lower N values in case of a draw)
Example C++11: godbolt
#include <type_traits>
#include <iostream>
#include <utility>
template<std::size_t N>
void foo() = delete;
template<>
void foo<5>() { std::cout << 5 << std::endl; }
template<>
void foo<10>() { std::cout << 10 << std::endl; }
template<>
void foo<15>() { std::cout << 15 << std::endl; }
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo<N>(), void())> : std::true_type {};
template<std::size_t N, std::size_t SearchRange = 10, std::size_t CurrentDistance = 0, class = void>
struct nearest_foo_specialized {
static const std::size_t index = 0; // an index for which foo<> is specialized, if value is true.
static const std::size_t distance = CurrentDistance; // distance from original N
static const bool value = false; // have we found a specialization yet?
};
// Found a match -> Report Success
template<std::size_t N, std::size_t SearchRange, std::size_t CurrentDistance>
struct nearest_foo_specialized<N, SearchRange, CurrentDistance, typename std::enable_if< CurrentDistance <= SearchRange && is_foo_specialized<N>::value >::type> {
static const std::size_t index = N;
static const std::size_t distance = CurrentDistance;
static const bool value = true;
};
// No match found -> recurse until SearchRange limit
template<std::size_t N, std::size_t SearchRange, std::size_t CurrentDistance>
struct nearest_foo_specialized<N, SearchRange, CurrentDistance, typename std::enable_if< CurrentDistance < SearchRange && !is_foo_specialized<N>::value >::type> {
typedef nearest_foo_specialized<N - 1, SearchRange, CurrentDistance + 1> down;
typedef nearest_foo_specialized<N + 1, SearchRange, CurrentDistance + 1> up;
static const std::size_t distance = down::distance < up::distance ? down::distance : up::distance;
static const std::size_t index = down::distance == distance && down::value ? down::index : up::index;
static const std::size_t value = down::distance == distance && down::value ? down::value : up::value;
};
// calls the nearest foo() specialization (up to 10 away from the specified N)
template<std::size_t N>
typename std::enable_if<nearest_foo_specialized<N>::value>::type call_nearest_foo() {
foo<nearest_foo_specialized<N>::index>();
}
template<std::size_t N>
typename std::enable_if<!nearest_foo_specialized<N>::value>::type call_nearest_foo() {
static_assert(N!=N, "No nearest foo() specialization found!");
}
int main() {
call_nearest_foo<7>(); // calls foo<5>()
call_nearest_foo<8>(); // calls foo<10>()
call_nearest_foo<11>(); // calls foo<10>()
call_nearest_foo<15>(); // calls foo<15>()
call_nearest_foo<25>(); // calls foo<15>()
// call_nearest_foo<26>(); // error: No nearest foo() (only searching up to 10 up / down)
}
I'm now learning a little about templates and templates in C++11, C++14 and C++1z. I'm trying to write a variadic class template with an inside class that will associate an int to every template argument - and have a constexpr method that returns its array representation.
Let's say that I have ensured that the template cannot receive two of the same type as an argument. I was thinking about doing it somewhat like this:
template <typename... Types>
struct MyVariadicTemplate {
//we know that all types in Types... are different
template <int... Values>
struct MyInnerTemplate {
//I need to make sure that sizeof...(Values) == sizeof...(Types)
constexpr std::array<int, sizeof...(Values)> to_array() {
std::array<int, sizeof...(Values)> result = {Values...};
return result;
// this is only valid since C++14, as far as I know
}
};
};
this code should be valid (if it's not, I'd love to know why). Now, I'd like to add another inner template:
template <typedef Type>
struct AnotherInnerTemplate {};
that has a public typedef, which represents MyInnerTemplate with one on the position of Type in Types... and zeros elsewhere - and here I'm lost. I don't know how to proceed
I would appreciate any hint on how that can be done - and if I'm heading towards the wrong direction, I hope somebody can give me a hint on how to do that.
I think what you're looking for is something like this.
#include <array>
#include <cstddef>
#include <iostream>
#include <type_traits>
template <typename NeedleT, typename... HaystackTs>
constexpr auto get_type_index_mask() noexcept
{
constexpr auto N = sizeof...(HaystackTs);
return std::array<bool, N> {
(std::is_same<NeedleT, HaystackTs>::value)...
};
}
template <typename T, std::size_t N>
constexpr std::size_t ffs(const std::array<T, N>& array) noexcept
{
for (auto i = std::size_t {}; i < N; ++i)
{
if (array[i])
return i;
}
return N;
}
int
main()
{
const auto mask = get_type_index_mask<float, bool, int, float, double, char>();
for (const auto& bit : mask)
std::cout << bit;
std::cout << "\n";
std::cout << "float has index " << ffs(mask) << "\n";
}
Output:
00100
float has index 2
The magic happens in the parameter pack expansion
(std::is_same<NeedleT, HaystackTs>::value)...
where you test each type in HaystackTs against NeedleT. You might want to apply std::decay to either type if you want to consider, say, const int and int the same type.
template <int size, int... Values> struct AnotherImpl {
using Type = typename AnotherImpl<size - 1, Values..., 0>::Type;
};
template <int... Values> struct AnotherImpl<0, Values...> {
using Type = Inner<Values...>;
};
template <class T> struct Another {
using Type = typename AnotherImpl<sizeof...(Types) - 1, 1>::Type;
};
Full:
template <class... Types> struct My {
template <int... Values> struct Inner {
constexpr std::array<int, sizeof...(Values)> to_array() {
return std::array<int, sizeof...(Values)>{Values...};
}
};
template <int size, int... Values> struct AnotherImpl {
using Type = typename AnotherImpl<size - 1, Values..., 0>::Type;
};
template <int... Values> struct AnotherImpl<0, Values...> {
using Type = Inner<Values...>;
};
template <class T> struct Another {
using Type = typename AnotherImpl<sizeof...(Types) - 1, 1>::Type;
};
};
auto main() -> int {
My<int, float, char>::Another<int>::Type s;
auto a = s.to_array();
for (auto e : a) {
cout << e << " ";
}
cout << endl;
return 0;
}
prints:
1 0 0
Is this what you want?
So suppose, that I have got a class, that contains functional object and in the constructor call I pass arguments, that are to be passed to the functional object some time later. Something like:
class Binder{
public:
Binder(functional_object, listOfParameters);
callFunctionalObject(); // calls functional object with given list of parameters
};
Before C++11 I could not use Variadic templates, so one would do:
struct none{};
template <typename T1, typename T2=none, typename T3=none>
class Binder{
public:
Binder(T1 functionalObject, T2 arg1=none(), T3arg3=none());
void callFunctionalObject();
private:
T1 m_functionalObject;
T2 m_arg1;
T3 m_arg2;
};
Where callFunctionalobject could be implemented as follows:
template<typename T1, typename T2, typename T3>
void Binder<T1,T2,T3>::callFunctionalObject(){
callImpl(m_functionalObject, m_arg1, m_arg2);
}
and callImpl would be overloaded to recognize objects of type none to pass proper amount of arguments to the functional object.
Now switching to C++11 I do not know how to implement the fact, that in private section I have got members, to which I have an direct access.
Could anyone explain me the way I can do the same using C++11 or C++14?
You should store a std::function and a std::tuple and then call the function on the tuple.
Here a working C++14 solution
#include <iostream>
#include <functional>
template<typename T1, typename ...T>
class Binder
{
public:
Binder(std::function<T1(T...)> f, std::tuple<T...> t) : m_functional_obj(f), m_parameters(t) {}
template<std::size_t ...I>
T1 callImpl(std::index_sequence<I...>)
{
return m_functional_obj(std::get<I>(m_parameters)...);
}
T1 callFunctionalObject()
{
return callImpl(std::index_sequence_for<T...>{});
}
private:
std::function<T1(T...)> m_functional_obj;
std::tuple<T...> m_parameters;
};
int test(int i)
{
std::cout << "test(" << i << ")" << std::endl;
return i + 1;
}
int main()
{
Binder<int,int> bibi(test, std::make_tuple<int>(2));
auto res = bibi.callFunctionalObject();
std::cout << "res is " << res << std::endl;
}
Live code
My example:
// Indices
template <std::size_t... Is>
struct Indices {};
template <std::size_t N, std::size_t... Is>
struct BuildIndices : BuildIndices <N - 1, N - 1, Is...> {};
template <std::size_t... Is>
struct BuildIndices<0, Is...> : Indices < Is... > {};
template<class FuncObject, class ... T>
class Binder
{
public:
Binder(FuncObject funcObject, T... args)
: m_funcObject(funcObject), m_arguments(std::make_tuple(args...))
{
}
void Call()
{
DoCall(BuildIndices<sizeof ... (T)> {});
}
private:
template<size_t... Ind>
void DoCall(Indices<Ind...>)
{
return m_funcObject(std::get<Ind>(m_arguments)...);
}
FuncObject m_funcObject;
std::tuple<T...> m_arguments;
};
void Foo(int, char)
{
}
int main()
{
Binder<void(*)(int, char), int, char> f(Foo, 1, 'd');
f.Call();
return 0;
}
The simplest way is to store an std::function object with already-set arguments using std::bind:
class Binder{
public:
template <typename T1, typename... T2>
Binder(T1 functionalObject, T2... args) : f(std::bind(functionalObject, args...)) {}
void callFunctionalObject() { f(); }
private:
std::function<void()> f;
};
void foo(int n, std::string s) {
std::cout << n << " " << s << std::endl;
}
int main()
{
Binder b(foo, 42, "test");
b.callFunctionalObject();
}
If you need something more advanced, then you might want to store the function arguments in and std::tuple and then use some template magic to unwrap it, but please specify what exactly do you need in the question.
P.S. See also "unpacking" a tuple to call a matching function pointer
Another day, another experiment with template meta-programming that's gone awry. I'm attempting to make an is_greater_than template that will take in two integral values N and M of type T.
template<typename T, T N, T M>
struct is_greater_than<void, N, M>;
template<typename T = std::enable_if<std::is_integral<T>::value, T>::value, T N, T M>
struct is_greater_than<T, N, M>
{
static const bool value = N > M;
};
Try as I might I can't seem to get this to work. Attempting to compile this yields 112 compiler errors. I have an ideone fiddle here: http://ideone.com/ch1j7b.
What am I doing wrong here? Any help would be appreciated!
Your usage of std::enable_if is wrong, it should be a separate template parameter (possibly unnamed):
#include <iostream>
#include <type_traits>
template<typename T, T N, T M,
typename = typename std::enable_if<std::is_integral<T>::value>::type>
struct is_greater_than:
public std::integral_constant<bool, (N > M)>::type
{
};
int main()
{
std::cout << is_greater_than<int, 1, 2>::value
<< is_greater_than<int, 1, 1>::value
<< is_greater_than<int, 2, 1>::value;
}
Note that I'm inheriting fromstd::integral_constant here, it'll define the value and type members for us based in its second argument (parenthesis around N > M are required).
Try this:
template<typename T, T N, T M, typename enable = void>
struct is_greater_than;
template<typename T, T N, T M>
struct is_greater_than<T,N,M,
typename std::enable_if<std::is_integral<T>::value>::type>
{
static const bool value = N > M;
};
int main()
{
bool a = is_greater_than<int, 11, 10>::value;
cout << boolalpha << a << endl;
}
Output:
true
Live code
This compiles fine in VS2010:
template<typename T, T M, T N>
struct is_greater_than;
template<typename T = std::enable_if< std::is_integral<T>::value, T >::value, T M = T(), T N = T()>
struct is_greater_than {
static const bool value = M > N;
};
You can test it with:
std::cout << is_greater_than<int,4,2>::value << std::endl;
std::cout << is_greater_than<std::string,"a","B">::value << std::endl;