我可以为一个类模板的函数模板成员做出单独的定义吗?

3
以下是我尝试做的一个最小代码示例,它能够运行,但不符合我的期望:
#include <string>
#include <type_traits>
#include <iostream>
struct string_tag {
    using R=const std::string;
};

struct int_tag {
    using R=const int;
};

template <bool TS>
class Wibble {
    public:
    template<typename TAG>
    typename TAG::R getValue(TAG);
};

template <bool TS>
template <typename TAG>
typename TAG::R Wibble<TS>::getValue(TAG) {
    if constexpr (std::is_same<TAG, string_tag>::value) {
        return "hello";
    }
    
    if constexpr (std::is_same<TAG, int_tag>::value) {
        return 42;
    }
}

// instantiate classes
template class Wibble<true>;
template class Wibble<false>;

int main () {
    Wibble<true> tw;
    Wibble<false> fw;
    std::cout << "tw string: " << tw.getValue(string_tag{}) << std::endl;
    std::cout << "tw int: " << tw.getValue(int_tag{}) << std::endl;
    std::cout << "fw string: " <<fw.getValue(string_tag{}) << std::endl;
    std::cout << "fw int: " << fw.getValue(int_tag{}) << std::endl;
}

这里有个Godbolt上的示例

我想要更改的部分是所有constexpr逻辑的函数模板定义看起来很丑陋。我希望能够单独定义TAG中的不同特化,但是这样做会导致redefinition of ...错误。

下面这样的语法会很好:

template<bool TS>
template<>
string_tag::R Wibble<TS>::getValue(string_tag) {
  return "hello";
}

但电脑说“不行”。


1
看起来你想要概念。你准备好使用C++20了吗?回复:“计算机说‘不’”+1 - Ted Lyngmo
不要只听我的话 - 我只是在喊流行语 :-) 我自己对 C++17 感到非常满意。 :-) - Ted Lyngmo
1
这个回答解决了你的问题吗?模板类成员函数的显式特化 - Quimby
1
那个问题要求首先对模板进行特化,正如所描述的那样,而这里并非如此。鉴于 getValue() 不依赖于 TS 参数,应该将其实现为一个单独的模板函数,可以正常地进行特化。类模板仍然可以定义自己的 getValue() 方法,仅仅调用“真正”的 getValue()。我期望现代 C++ 编译器能够优化掉额外的函数调用。 - Sam Varshavchik
1
@VorpalSword 只要您仍然将标签用作函数参数,就可以通过重载获得不同的返回类型。演示。这是否达到了您想要的效果? - cigien
显示剩余5条评论
1个回答

5

经过思考,阅读语言规范等等,以下是我的想法:

  1. 必须特化类模板才能特化成员函数模板。这一点是无法通过概念来克服的,至少我还没有找到方法。我猜你不想为每个 TS 情况复制代码。也许可以使用一些 Alexandrescu 风格的元编程技术自动完成,但我一时想不到什么。

  2. 与其使用模板,重载是一个不错的选择,但我猜测你想在类外部添加它们,而不是在类内部添加...

  3. 然后我想起了 David Wheeler:“计算机科学中的所有问题都可以通过引入另一个层次的间接性来解决。”所以让我们加上一层:

namespace detail
{
template<typename TAG> auto getValue(TAG);

template<>
auto getValue<string_tag>(string_tag)
{
    return "hi";
}


template<>
auto getValue<int_tag>(int_tag)
{
    return 42;
}

template<>
auto getValue<double_tag>(double_tag)
{
    return 1324.2;
}

}

template<bool TS>
template<typename TAG>
auto Wibble<TS>::getValue(TAG t)
{
    return detail::getValue(t);
}

希望这有帮助。

https://godbolt.org/z/GsPK4MP8M


非常感谢!这个完美地运行了。赢得了与编译器交互中“合理并按照我的方式进行”这种罕见的例子;-) - VorpalSword

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接