1

I have always read that you can define a trait like

enum MyEnum { val_1, val_2, val_3 };

template< typename T > 
struct my_trait { 
  static const MyEnum value = MyEnum::val_1;
};

and then specialise it

template<> 
struct my_trait < void >{ 
  static const MyEnum value = val_3; 
};

When I have tried it I always get a linker error since the static member is not defined, so I have to explicitly specialise it in the source file as

MyEnum my_trait < void >::value = val_3;

and change the definition in the header to

template<> 
struct is_void< void >{ 
  static const MyEnum value; 
};

Is there any way to define the trait directly in the header without having to redefine it in the header?

Lezkus
  • 160
  • 1
  • 12

2 Answers2

0

Not exactly an answer to your question but... in your example (if you can use a C++11 compliler) you can use std::integral_constant.

A full example

#include <iostream>
#include <type_traits>

enum MyEnum { val_1, val_2, val_3 };

template< typename T > 
struct my_trait : public std::integral_constant<MyEnum, MyEnum::val_1>
 { };

template<> 
struct my_trait<void> : public std::integral_constant<MyEnum, MyEnum::val_3>
 { };

int main ()
 {
   std::cout << my_trait<void>::value << std::endl; // print 2 (aka val_3)
   std::cout << my_trait<int>::value << std::endl;  // print 0 (aka val_1)
 }
max66
  • 65,235
  • 10
  • 71
  • 111
  • I just presented an example. The real code I am working with is a little bit more complicated. – Lezkus Apr 14 '17 at 13:25
  • 1
    @Lezkus - I see... Well, I suppose you should propose a minimal example that show how to get the error – max66 Apr 14 '17 at 13:26
  • I edited the question with the actual use case. I though that the formulation with any other type would be equivalent, but apparently it is not. – Lezkus Apr 14 '17 at 13:33
  • @Lezkus - answer modified to use `My_enum` – max66 Apr 14 '17 at 13:40
  • I see, that's a very good point. Does this generalise to a situation like this one: http://stackoverflow.com/questions/43190790/linking-against-a-shared-library-with-explicitly-instantiated-templates ? – Lezkus Apr 14 '17 at 13:44
  • @Lezkus - I suppose you can define `static constexpr const char charsStr[] = "chars";` as global constant and inherit from `std::integral_constant` – max66 Apr 14 '17 at 13:54
0

This will cause linker error:

std::cout << &is_void<void>::value << std::endl;

because you odr-use value - it means you want its address. I am not sure but this might also happen with references - as they might be implemented internally as pointers. So until c++14 you would have to define your value inside implementation file.

Since C++17 you can use inline variables to keep it all in one place even if you need to odr-use it:

template< typename T > 
struct is_void{ 
  inline static const bool value = false;
  ^^^^^^ 
};
marcinj
  • 48,511
  • 9
  • 79
  • 100