lundi 25 janvier 2016

Constraint API template types neatly

I have a template API function in my class called template<typename T> T Get(/*stuff*/);. My source file implements this function for a certain list of T types. If the user wants to use a type that I have not implemented, then I want the result to be a compile error, and not a linker error. I don't care much about the compile message yet. Here's what I've got so far:

MyClass.h

#pragma once

#define API_TYPE(X) \
  template<> struct Implemented<X> : public API<X> {}

namespace MyClassAPI
{
  template<typename T> struct API
  {
    static T Get(const T&);
  };

  template<typename T> struct Implemented {};
  API_TYPE(bool);
}

class MyClass
{
  template<typename T> friend struct MyClassAPI::API;

  public:
    template<typename T> T Get(const T& t) const
    {
      return MyClassAPI::Implemented<T>::Get(t);
    }
};

MyClass.cpp

#include "MyClass.h"

namespace MyClassAPI
{
  template<typename T> T API<T>::Get(const T& t) { return t; }
  //template struct API<bool> //Why do I need this?
}

main.cpp

#include "MyClass.h"
#include <iostream>
#include <cassert>

using namespace std;

// Main File
int main() {
  MyClass c;
  cout << "Getting true: " << c.Get(true) << endl;
  return 0;
}

So my question is about a line in MyClass.cpp. Why do I need to replicate the API<bool> explicit declaration in the source file with template struct API<bool>;? Shouldn't it know to expand the template function definition from the header file's declaration?

Also, is there a way to do this without declaring my accepted type list twice?

Error without the line:

g++ -Wfatal-errors -Werror -std=c++11 -g -O0 -Wall -c MyClass.cpp -o MyClass.o
g++ -Wfatal-errors -Werror -std=c++11 -g -O0 -Wall test.cpp MyClass.o -o test
/tmp/ccVxp4F3.o: In function `bool MyClass::Get<bool>(bool const&) const':
MyClass.h:25: undefined reference to `MyClassAPI::API<bool>::Get(bool const&)'
collect2: error: ld returned 1 exit status
make: *** [test] Error 1

Aucun commentaire:

Enregistrer un commentaire