The code below fails (as expected). What bothers me is the error message. It does not clearly say what the problem is. I would have expected something like “cannot convert from const char* to int”
. Instead, it says "cannot convert from 'initializer list' to 'B<int>'"
, which becomes less clear when other, complex, types are involved.
How do I add a custom error message? The actual class is much more complicated.
#include <vector>
template< typename T >
class B
{
std::vector<T> v;
public:
B( std::initializer_list<T> il ) : v{ il } {}
};
int main()
{
B<int> b{ "a","b","c" }; // fails with cannot convert from 'initializer list' to 'B<int>'
}
If you only want to have a std::initializer_list<T>
constructor then one thing you can do is provide a variadic template constructor and then have a static_assert
inside the constructor that gives the error message that you want. This works because if you provide anything other then an std::initializer_list<T>
the constructor will be a better match and the assert will fire. That would look like
#include <vector>
template< typename T >
class B
{
std::vector<T> v;
public:
B( std::initializer_list<T> il ) : v{ il } {}
template <typename... Args>
// the sizeof...(Args) < 0 is needed so the assert will only fire if the constructor is called
B(Args...) { static_assert(sizeof...(Args) < 0, "This class can only be constructed from a std::initializer_list<T>"); }
};
int main()
{
//B<int> b1{ "a","b","c" }; // uncomment this line to get static_assert to fire
B<int> b2{ 1,2,3 };
}