how to prevent template argument deduction

In C++17, is there a way to prevent template argument deduction from a call to a call class constructor?

In the following code, I define a template class with an argument T that is meant to be the "precision" (float, double, long double) of the data stored. I want it to be double by default and I don't want the value given to the constructor to define the type of T even when it is not explicitly specified. I also want objects with the same precision to be of the same type (so having a second template parameter is not an option)

By the way, this is how it worked the situation before C++17. Does it mean that backward compatibility has been lost?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

template <typename T = double>
class heading{
public:
    T value;
    public:
    heading(T h):value(h+0.333){}
};


int main(){

heading a(2); //this creates a heading<int>  but I want a  heading<double>
              //unless explicitly specified

std::cout << a.value << std::endl;
}
Last edited on
Ok, I found this solution. It works because template argument deduction doesn't process decltype() expressions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

template <typename T = double>
class heading{
public:
    typedef decltype(T()) S;
    T value;
    public:
    heading(S h):value(h+0.333){}
};


int main(){

heading a(2); //now this does not define T as an int!
              //and the default type double is used

std::cout << a.value << std::endl;
}
Last edited on
Two ways.
1. Add a user-defined deduction guide that maps any T to double. CTAD only occurs if no template argument list appears.
1
2
template <typename T>
heading(T) -> heading<double>;


2. Change the type of the converting constructor's parameter:
heading(std::common_type_t<T> h):value(h+0.333){}

This is a old library author's trick to disable function template argument deduction. std::common_type_t<T> is equivalent for these purposes to the identity meta-function. Same idea as the decltype hack.

Maybe suggestion 1. isn't the best idea. I am not very familiar with this feature.
Last edited on
If you plan to use your template class only for a few types, you could also consider to implement it for those tyoes only:

heading.hpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef HEADING_HPP
#define HEADING_HPP


template <typename T>
class heading {
public:
    T value;

    heading(T value_arg);
};


#endif // HEADING_HPP 


heading.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "heading.hpp"


template<typename T>
heading<T>::heading(T value_arg)
    : value { value_arg + 0.333 }   // use rounded parenthesys to avoid warnings
{

}


template class heading<float>;
template class heading<double>;
template class heading<long double>;


main.cpp:
1
2
3
4
5
6
7
8
9
#include "heading.hpp"
#include <iostream>

int main()
{
    // Does no compile!
    heading myh(2);     // undefined reference to heading<int>::heading(int)
    std::cout << myh.value << '\n';
}


While this version of main.cpp compiles:
1
2
3
4
5
6
7
8
#include "heading.hpp"
#include <iostream>

int main()
{
    heading myh(2.0);
    std::cout << myh.value << '\n';
}


Output:
2.333

Topic archived. No new replies allowed.