Using explicit template instantiation on class function to restrict template parameters

Ok, so I'm basically making a class that is supposed to be similar to var in javascript. It's gonna be able to hold only four or five very specific types, and I was writing the constructor, and the constructor is exactly the same for all the types, but I don't want to use just a normal templated constructor, because then it will accept a bunch of types I don't necessarily want, right? So, I remembered that there is supposed to be a way to implement template classes outside of the header file by explicitly instantiating the template function or class in the header, and then implementing it in the .cpp, however this makes it so only those types that you explicitly instantiated are able to be used. This is the exact behavior I want.

The only problem is that I have absolutely know idea how I would do that specifically for a function inside of a class, or for the constructor, because the class itself is not a template class, just the function.

I was wondering if anyone knew how that's supposed to work..? I would greatly appreciate some example specific to my situation.


My code would look something like this, I think.

var.hpp:
1
2
3
4
5
6
7
8
9
10
11
12
#pragma once

class var
{
  // ...

  template <int> var(int x); // explicit instantiation 1
  template <float> var(float x); // explicit instantiation 2
  template <std::string> var(std::string x); // explicit instantiation 3

  // ...
};


var.cpp:
1
2
3
4
5
6
7
8
#include "var.hpp"

// ...

template <typename type>
var::var<type>(type value): _type(typeid(type)), _value(value) {}

// ... 




main.cpp:
1
2
3
4
5
6
7
8
9
10
#include <vector>
#include <string>
#include "var.hpp"

int main()
{
  var x( 2356 ); // fine
  var y( std::string("hello!") ); // fine
  var z({ 12 , 345, 66 }); // not fine! error!
}
C++20:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <string>
#include <concepts> // C++20

struct var
{
    template < std::integral T > /* explicit */ var(T) noexcept : type(INTEGRAL) {} // constrained
    template < std::floating_point T > /* explicit */ var(T) noexcept : type(FLOATING_POINT) {} // constrained

    /* explicit */ var( const std::string& ) noexcept : type(STRING) {} // overloaded
    /* explicit */ var( const char* ) noexcept : type(STRING) {} // overloaded

    enum type_t { INTEGRAL, FLOATING_POINT, STRING };
    type_t type ;
};

int main()
{
    var vi = 123LL; // vi.type == var::INTEGRAL
    var vd = 23.456 ; // vd.type == var::FLOATING_POINT
    var vs = "abcd" ; // vs.type == var::STRING
    // var bad = std::cout.rdbuf() ; // *** error *** no viable constructor
}
I don't see why you need a template at all. Don't you need to do different things with different types?

Consider:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once

class var
{
  // ...
protected:
  template <typename type>
  var(type value, bool): _type(typeid(type)), _value(value) {} // Note: extra parameter bool for differentiation

public:
  var(int x) : var(x, true) {}
  var(float x) : var(x, true) {}
  var(std::string x) : var(x, true) {}

  // ...
};
But I think the gain is that minimal that you may do this without template...
It's gonna be able to hold only four or five very specific types


Have you considered std::variant?

https://en.cppreference.com/w/cpp/utility/variant
@JLBorges
I forgot to say that I can’t use C++20… but otherwise… maybe. However, it seems like I’m going to be just reimplementing the constructor each time again, which kind of defeats the purpose a bit… (trying to reduce the amount of code I write without resorting to, like, macros or something..)

@corder777
I was trying to think of ways to reduce the amount of code I have to write out… I’m lazy I guess? Also makes it easier if I add a type and stuff later on..
the individual implementations would actually just look exactly the same. I basically am just assigning to an std::any and getting the type. I don’t really do anything special in the constructor…

@seeplus
Hm.. I mean, I was using an std::any internally, but - making a closer comparison of the two - std::variant probably IS a better choice, maybe making things a little easier.
That being said, it still does not do everything I’m going to make it do, like specific operations like index operator([]). Basically it’s just gonna be a really thin wrapper around an any or variant. variant might solves the type constraint problems though.. that might just work- I’ll have to check those docs just to make sure though.
Sorry about the late response btw, I for some reason decided to make the post like right before a class… 😬
Ok, std::variant is perfect. I completely forgot that it was type safe.

Thanks everyone!
highwayman wrote:
I can’t use C++20

But you can use C++17. Strange.

Is it because you don't have a C++20 capable compiler? Or your instructor doesn't allow it?

The former is easily corrected, the latter shows someone needs to stop living in the past. C++20 is here, and C++23 is well on its way of being approved. Some current compilers already have partial C++23 support available.

https://en.cppreference.com/w/cpp/23

One C++23 proposal, clarifying the status of the C headers, is long over-due.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2340r1.html
I don't have an instructor - it's actually because the environment I use is kinda fixed, and I don't have root/sudo privileges, so I have to spend forever find solutions to my problems that don't use sudo, which is massively annoying.

I'm on https://replit.com. If I remember correctly, I can get it to have the correct compiler version, but getting the correct std library to be used with all the new headers...I'm not even sure how I got the correct library last time, and I'm pretty sure I ended up having some sort of linking problem that is apparently common and trivial to fix, but only if you have root/sudo perms

It pisses me off

:(
Last edited on
I'm a Winders kinda guy so any advice I could give is irrelevant about how to get a usable C++20 compiler. I'd bet there are enough *nix(?) people here who could lend a digital finger or hand to help if it is possible to get around your permissions issue.
That's probably true. I might try and find that repl and post something in the *nix(yup) board at some point.

..I'm just gonna have to remember how I even got to that point before XP
Registered users can post here. Sign in or register to post.