-1
class holder
{
public:
     template<class T>
     T get()
     {
        #if (typeid(T) == typeid(object1)){
          return obj1;
        }
        #elif (typeid(T) == typeid(object2)){
          return obj2;
        }
       // #else{
          // return nullptr; // sory my mistake. ignore it.
       // }
       #endif
    }

private:
    object1 obj1;
    object2 obj2;
}

Want get a object by templete, But, it not work. why and how to modify it.? I know Use it like this:

holder a;
object1 obj1 = a.get<object1>();
tocky
  • 107
  • 1
  • 7
  • 1
    The preprocessor has finished it's run long before the compiler and type system are even made aware of the template. The way you try to get at your desired behavior is a non-starter. Forget the preprocessor even exists whenever you care about types. – StoryTeller - Unslander Monica Nov 08 '17 at 06:33
  • What is the application for the `holder` object? Are you attempting to switch types at runtime? You may be better off creating a getter for each type of object, e.g. `object1& getObj1();` and `object2& getObj2();` – Matt Nov 08 '17 at 06:38
  • 1
    https://stackoverflow.com/questions/34460480/c-universal-getter-for-class/34460698#34460698 – Artur Pyszczuk Nov 08 '17 at 06:51

1 Answers1

4

Using macro with template is not a good idea. You could use full template specialization for this. e.g.

class holder
{
public:
     template<class T>
     T get() {
         return {};
     }
private:
    object1 obj1;
    object2 obj2;
};

template<>
object1 holder::get<object1>() { return obj1; }
template<>
object2 holder::get<object2>() { return obj2; }

LIVE

BTW: get is returning by value, so I suppose returning nullptr won't work. In the primary template I returned a value-initialized object. If it shouldn't be invoked at all you can mark it as delete as @StoryTeller suggested; then you'll get an error at compile-time.

From C++17 you can use if constexpr, which might be more close to your original idea.

class holder
{
public:
     template<class T>
     T get() {
         if constexpr (std::is_same_v<T, object1>) 
             return obj1;
         else if constexpr (std::is_same_v<T, object2>) 
             return obj2;
         else
             return {};
     }
private:
    object1 obj1;
    object2 obj2;
};

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Bear in mind, there will be no default `nullptr` version in this case, because you are returning objects of type T. It's very likely that you want the function signature to be `T& get();`, though bear in mind that you will need to keep the `holder` object in scope while the reference is being used. – Matt Nov 08 '17 at 06:36
  • @Matt - I think the `nullptr` approach by the OP is a kludge to handle illegal use. A hard error is much preferable. songyuanyao, btw, if you `delete` the primary template specialization, the error will pop up much faster than just in link time. – StoryTeller - Unslander Monica Nov 08 '17 at 06:39
  • sorry, I made a mistake. NOT nullptr. My intention is the shared_ptr. it's pseudo-code. – tocky Nov 08 '17 at 08:32
  • @user2163635 Well, depends on your intent, you can choose either way showed in the BTW part. – songyuanyao Nov 08 '17 at 08:36
  • Just now, I test it. But it complier with LNK 2005. Aready defined.because the template method DEFINED at header file. How to solve it ? Thanks. – tocky Nov 08 '17 at 09:54
  • @user2163635 Could you make an [MCVE](https://stackoverflow.com/help/mcve) which could reproduce the error? – songyuanyao Nov 08 '17 at 10:01
  • SOVE IT,AS https://stackoverflow.com/questions/5417215/function-template-specialization-compile-error – tocky Nov 09 '17 at 07:26