How to call a templated function if it exists, and something else otherwise?

后端 未结 7 458
忘掉有多难
忘掉有多难 2021-01-30 10:58

I want to do something like

template 
void foo(const T& t) {
   IF bar(t) would compile
      bar(t);
   ELSE
      baz(t);
}
7条回答
  •  时光说笑
    2021-01-30 11:37

    EDIT: I spoke too soon! litb's answer shows how this can actually be done (at the possible cost of your sanity... :-P)

    Unfortunately I think the general case of checking "would this compile" is out of reach of function template argument deduction + SFINAE, which is the usual trick for this stuff. I think the best you can do is to create a "backup" function template:

    template 
    void bar(T t) {   // "Backup" bar() template
        baz(t);
    }
    

    And then change foo() to simply:

    template 
    void foo(const T& t) {
        bar(t);
    }
    

    This will work for most cases. Because the bar() template's parameter type is T, it will be deemed "less specialised" when compared with any other function or function template named bar() and will therefore cede priority to that pre-existing function or function template during overload resolution. Except that:

    • If the pre-existing bar() is itself a function template taking a template parameter of type T, an ambiguity will arise because neither template is more specialised than the other, and the compiler will complain.
    • Implicit conversions also won't work, and will lead to hard-to-diagnose problems: Suppose there is a pre-existing bar(long) but foo(123) is called. In this case, the compiler will quietly choose to instantiate the "backup" bar() template with T = int instead of performing the int->long promotion, even though the latter would have compiled and worked fine!

    In short: there's no easy, complete solution, and I'm pretty sure there's not even a tricky-as-hell, complete solution. :(

提交回复
热议问题