Jump to content
  • Advertisement
Sign in to follow this  
Khatharr

Template Specialization

This topic is 977 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I has a function:

template <class T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
T function(const std::string& requestString) {
  //things happen
}

Clearly it's only supposed to accept numeric types, but now I want to add a specialization so that it can also handle std::string using different internal logic.

 

I haven't messed with specialization before, but what I tried based on my reading was this:

template<> std::string function<std::string>(const std::string& requestString) {
  //tomfoolery
}

The compiler doesn't seem to like that. It says that the template can't match the type. I'm thinking this means that it's upset because std::string isn't arithmetic, as is specified by the original. I figured I should declare an "empty" template (just <class T> and no function body contents) and change the arithmetic one to a specialization, but then (predictably) it complained that <int> was ambiguous between the empty one and the arithmetic one.

 

Anyone know how I can do this?

Share this post


Link to post
Share on other sites
Advertisement
template<typename T>
class acceptsType
{
    template<typename T2, bool isAritmetic = false>
    class helper
    {
    public:

        static const bool value = false;
    };

    template<typename T2>
    class helper<T2, true> // every aritmetic value is accepted
    {
    public:

        static const bool value = true;
    };

    template<>
    class helper<std::string, false> // otherwise, only std::string is accepted
    {
    public:
        static const bool value = true;
    };

public:

    static const bool value = typename helper<T, std::is_arithmetic<T>::value>::value;
};

The idea I had involved generating a helper-template class, that acts as a replacement of "is_aritmetic" when you declare your template function:

template<class T, typename = typename std::enable_if<acceptsType<T>::value, T>::type> // exchange here
T function(const std::string& requestString)
{
    //things happen
}

template<>
std::string function<std::string>(const std::string& requestString) // compiles now
{
    //tomfoolery
}

template<>
int function<int>(const std::string& requestString)
{
}

This compiles for me. I don't know if its the smoothest solution, but at least it gives you explicit control over ie. if you want to add more types without it getting too complicated.

 

EDIT:

 

Also, unless you are stuck on pre-C++11, why even go to the trouble of handling this using std::enable_if? If I get it correctly you want to have an compile error if an user tries to use a type thats not aritmetic(or std::string). Why not use an static_assert instead?

template<class T>
T function(const std::string& requestString)
{
    static_assert(std::is_arithmetic<T>::value, "Function only accepts aritmetic values (int, float, ...). Alternatively, try the std::string overload.");
}

Allows you to have an error message that is more clear, and makes specializing way easier.

Edited by Juliean

Share this post


Link to post
Share on other sites

Also, unless you are stuck on pre-C++11, why even go to the trouble of handling this using std::enable_if? If I get it correctly you want to have an compile error if an user tries to use a type thats not aritmetic(or std::string). Why not use an static_assert instead?


std::enable_if is already C++11. You might be thinking of the old boost::enable_if. That said, I'm not sure about the exact semantics of static_assert but can it really be used to trigger SFINAE, because that's usually the whole point of enable_if.

Khatharr: You might want to take a look at the notes in the cppreference.com documentation. It's not the exact case but might be part of the problem.
I would also try to use enable_if like this

template <class T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type function(const std::string& requestString) // ...
instead. The only times I have used it, I used it like that.

Share this post


Link to post
Share on other sites


std::enable_if is already C++11. You might be thinking of the old boost::enable_if. That said, I'm not sure about the exact semantics of static_assert but can it really be used to trigger SFINAE, because that's usually the whole point of enable_if.

 

Ah right, wasn't sure if enable_if is already in C++11 or not.

 

No, static_assert won't trigger SFINAE, but that was kind of my point - as with the code example given, I don't see much points in him using SFINEA. What he shows and describes is a function that should fail to instantiate if a incompatible type is used - which is what static_assert does, but only with a better error output. I posted both my solution and the comment towards static_assert based on whether he really wants to use SFINEA here, or not :)

Share this post


Link to post
Share on other sites
I would use SFINAE like this:
template<typename T> void Func(T x, typename std::enable_if<std::is_arithmetic<T>::value, bool>::type = true) {
	cout << "interger type = " << typeid(T).name() << endl;
	}

void Func(std::string) {
	cout << "string type" << endl;
	}
And beaten to it by BitMaster. You can use enable_if as either a parameter passed (often using a default value that is never used) or as a return value. Whichever syntax you prefer (both are kinda messy IMHO). Edited by Ryan_001

Share this post


Link to post
Share on other sites

No, static_assert won't trigger SFINAE, but that was kind of my point - as with the code example given, I don't see much points in him using SFINEA. What he shows and describes is a function that should fail to instantiate if a incompatible type is used - which is what static_assert does, but only with a better error output. I posted both my solution and the comment towards static_assert based on whether he really wants to use SFINEA here, or not smile.png


Yes, but the point of template specialization is in general that you don't want to just restrict it to specific types, you want radically different behavior for some types which you cannot do unless you provide a completely different implementation for those types.
Edit: Actually I think I see what you want to do now. Specialize for std::string as originally planned but insert the static_assert into the unspecialized template part. Yes, that would work. Although if I had the time I would try to investigate why the current scheme does not work. You don't always have such a workaround and there might be some easy skill points to get.

Ryan_001: that won't work in this scenario since the template parameter is only used for the return value and you have to call it function<myType>(...). If the template parameter was used as a function parameter, it could be done like that. Edited by BitMaster

Share this post


Link to post
Share on other sites


Yes, but the point of template specialization is in general that you don't want to just restrict it to specific types, you want radically different behavior for some types which you cannot do unless you provide a completely different implementation for those types.

 

Sure, I agree, might even been that I misunderstood the original question a bit. I thought he wanted to support only is_aritmetic for the base function, and have only a limitied array of other specialisations (of previously known types) like std::string.

 

In the other case, that he only wants the base function not being callable other than with is_aritmetic compatible types, while still being able to add an arbitrary number of specialisations (possibly by other users), I'd make an even stronger argument for static_assert and against SFINEA.

 

I'm feeling even more confused about the use of std::enable_if now in the first place, so unless I'm right and its misused here, somebody please explain to me what it does in this particaluar code example.

Share this post


Link to post
Share on other sites

In the existing function it prevents compilation if the type is not arithmetic. The function body handles arithmetic types, but I also want to start supporting specific non-arithmetic types using the same signature but different function bodies. (Beginning with std::string, yes.)

 

This is in VS, so the way I have it now does the red underline at the call site when a non-supported type is entered, which is sort of what I'm after.

 

How would you go about using static_assert for this?

Share this post


Link to post
Share on other sites
I don't think one can decide whether it's misused or not without more context. The thing I would really try to fix it is my suggestion from #3. I have never seen any enable_if used as a defaulted template parameter before and that note from cppreference makes me doubly cautious about that...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!