Search code examples
c++templatestemplate-argument-deduction

Failing to deduce type from enum in a C++ template class


I have the following reduced example where I try to map from an enumeration that I created (f32) to a native-type (float). I am trying to extend based on this answer.

#include <any>
#include <iostream>

enum class Scalar {
    f32,
    i32
};

template <enum Scalar> struct DeduceNative;

template <>  struct DeduceNative<Scalar::f32> {
    using type = float;
};

template <>  struct DeduceNative<Scalar::i32> {
    using type = int;
};


void example(){
    DeduceNative<Scalar::i32>::type izero(0);
    DeduceNative<Scalar::f32>::type fzero(0);
    
    std::cout << izero << " ";
    std::cout << fzero << "\n";
}

#if 1
template <enum Scalar>
struct Zero {
    DeduceNative<Scalar>::type value() { return 0; }
};

void working_draft(){
    Zero<Scalar::f32> fzero;
    Zero<Scalar::f32> izero;
    std::cout << fzero.value() << " " <<  izero.value() << std::endl;
}
#endif

int main(){
    example();
    return 0;
}

The working_draft fails to compile (with the error below) while the example is working as intended. Why is the type not being deduced properly in working_draft case?

<source>:24:24: error: type/value mismatch at argument 1 in template parameter list for 'template<Scalar <anonymous> > struct DeduceNative'
   24 |     DeduceNative<Scalar>::type value() { return 0; }

Solution

  • You want this

    template <Scalar sc>
    struct Zero {
        typename DeduceNative<sc>::type value() { return 0; }
    };
    

    Zero has a non-type template argument. enum Scalar is one but it is unnamed. Then you tried DeduceNative<Scalar> which makes no sense. Scalar is not the name of the template argument, but of the enum type. You also need typename keyword because its a dependant name.

    PS: Nothing is being deduced in your code. Deduction is when the arguments are not explicitly given but infered from eg function arguments.