5

I'm trying to make a class which will work with specific data types and I want to have a compile-time error when data type is not supported.

I tried to specialize templates like this.

template<>
float Foo::get<float>(const std::string& key)
{
    return std::stof(key);
}

And put a std::static_assert in the generic function because I only need these types that are specified.

template<class T>
T Foo::get(const std::string&)
{
    static_assert(false, "unsupported data type");
    return T(0);
}

Unfortunately I get the compile error (static assert failed) even if I have a specialized function for this type.

I found a way to do it for the specific types only but it looks kinda stupid and its not generic.

T Foo::get(const std::string&)
{
    static_assert(
            std::is_same<T,float>::value ||
            std::is_same<T,double>::value ||
            std::is_same<T,bool>::value ||
            std::is_same<T,uint32_t>::value ||
            std::is_same<T,int32_t>::value ||
            std::is_same<T,std::string>::value,
            "unsuported data type");
    return T(0);
}
Petar Velev
  • 2,305
  • 12
  • 24
  • There's fancy trick (`always_false::value`) for that purpose, but I think it's simpler to just not define the primary template. – cpplearner Jul 06 '17 at 11:21

2 Answers2

1

You may do

template <typename> struct AlwaysFalse : false_type {};


template<class T>
T Foo::get(const std::string&)
{
    static_assert(AlwaysFalse<T>::value, "unsupported data type");
}

So the assert is template dependent.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I am tempted to close as duplicate of this: https://stackoverflow.com/questions/30078818/static-assert-dependent-on-non-type-template-parameter-different-behavior-on-gc which contradicts your answer. Any thoughts? – bolov Jul 06 '17 at 11:37
  • @bolov: It doesn't contradict my answer. `AlwaysFalse::value` **is** dependent of `T`. And we might construct `dummy` class and specialize `struct AlwaysFalse : true_type {};` to have a valid instantiation of `Foo::get`. – Jarod42 Jul 06 '17 at 11:43
  • well.. there's that quote: "Inside a template, some constructs have semantics which may differ from one instantiation to another. Such a construct depends on the template parameters." – bolov Jul 06 '17 at 11:46
  • 1
    @bolov:`AlwaysFalse::value` depend of `T`, it could have different value (as with my specialization with `dummy`). ON the contrary,`false` cannot change value depending of `T`. – Jarod42 Jul 06 '17 at 11:50
1

You can make static_assert depending on the template parameter T, then it won't be evaluated until the time of instantiation, i.e. the time the exact type is explored as template argument. e.g.

template<class T>
T get(const std::string&)
{
    static_assert(!std::is_same<T, T>::value, "unsupported data type");
    return T(0);
}

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • I prefer the `static_assert(sizeof(T) == -1, "unsupported data type");` for being more compact. Also i believe this is the more common approach. – K. Kirsz Jul 06 '17 at 11:25
  • I found and tried this but it is still giving me this compile time errors. Where should be my specialized functions in the .cpp or in the header. Does that even matter? – Petar Velev Jul 06 '17 at 11:27
  • @PetarVelev It matters indeed. At least a declaration for the explicit specialisation must be visible at the point where it's used, or the compiler will instantiate an implicit specialisation from the primary template (which will give the error). – Angew is no longer proud of SO Jul 06 '17 at 11:30
  • It should work. See here: https://ideone.com/RVH3ML – K. Kirsz Jul 06 '17 at 11:31
  • @Angew I thought that the problem might be something like this. But if I the function logic in the header i get weird errors like this `.....h:75: multiple definition of 'bool... ` – Petar Velev Jul 06 '17 at 11:35
  • 1
    @PetarVelev A template specialisation is not a template, and thus follows normal function definition rules. If you want to put it in a header, it has to be marked `inline`. – Angew is no longer proud of SO Jul 06 '17 at 11:37
  • I am tempted to close as duplicate of this: https://stackoverflow.com/questions/30078818/static-assert-dependent-on-non-type-template-parameter-different-behavior-on-gc which contradicts your answer. Any thoughts? – bolov Jul 06 '17 at 11:37
  • 1
    @K.Kirsz: for `static_assert(sizeof(T) == -1`, you cannot then have valid instantiation, so the program is technically ill formed. `std::is_same::value` can be specialized to have valid `get`. – Jarod42 Jul 06 '17 at 11:47
  • @Angew Thank you! Your last comment helped me. – Petar Velev Jul 06 '17 at 11:50
  • [This code is ill formed with no diagnostic required.](https://stackoverflow.com/a/44848147/4899740) – Serikov Jul 06 '17 at 15:12