Search code examples
c++multiple-definition-error

Getting "Multiple definition" with no apparent reason


The problem is clear enough from the title. Here's the code:

TimeTask.hpp:

#pragma once
#include <locale>
#include <codecvt>
#include <chrono>

namespace TimeTask {

static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter;

std::tm * to_date(
    int day, int month, int year,
    int hours = -1, int minutes = -1, int seconds = -1
) {
    time_t rawTime = time(0);
    std::tm * tInfo = localtime(&rawTime);
    tInfo->tm_mday  = day;
    tInfo->tm_mon   = month - 1;
    tInfo->tm_year  = year - 1900;

    if(hours >= 0)
        tInfo -> tm_hour = hours;
    if(seconds >= 0)
        tInfo -> tm_sec = seconds;
    if(minutes >= 0)
        tInfo -> tm_min = minutes;

    return tInfo;
}

std::string from_time_point(const std::chrono::system_clock::time_point &arg) {
    time_t time = std::chrono::system_clock::to_time_t(arg);
    return ctime(&time);
}

}

Task.hpp:

#pragma once

#include <string>
#include "TimeTask.hpp"

class Task
{
public:
    Task(
        const std::basic_string<wchar_t>&,
        const bool&,
        const std::chrono::system_clock::time_point&
    );
    Task();

    std::basic_string<wchar_t>                  description;
    bool                                        executed;
    std::chrono::system_clock::time_point       date;

    std::wstring towString();
};

Task.cpp:

#include "Task.hpp"
#include <sstream>    

Task::Task(
    const std::basic_string<wchar_t>& description,
    const bool& executed,
    const std::chrono::system_clock::time_point& date
):
    description(description),
    executed(executed),
    date(date) { }

Task::Task():
    Task( L"Task", false, std::chrono::system_clock::now() ) { }

std::wstring Task::towString() {
    std::wostringstream retval(L"");

    retval << L"Task:\t"
           << description
           << L"\nPerformed:\t"
           << std::boolalpha << executed;    

    retval << TimeTask::converter.from_bytes(TimeTask::from_time_point(date));

    return retval.str();
}

main.cpp:

#include    <iostream>
#include    <type_traits>
#include    <vector>
#include    <list>
#include    "Task.hpp"

int main () {
    Task t1(L"Lezione programmazione",
            false,
            std::chrono::system_clock::from_time_t(
                std::mktime(TimeTask::to_date( 5,5,2017)) ));

    Task t2(L"Lezione programmazione",
            false,
            std::chrono::system_clock::from_time_t(
                std::mktime(TimeTask::to_date( 1,10,2017)) ));

    Task t3(L"Lezione programmazione",
            false,
            std::chrono::system_clock::from_time_t(
                std::mktime(TimeTask::to_date( 1,17,2017 )) ));

    std::list   <Task>    agenda1 = { t1, t2, t3 };
    std::vector <Task>    agenda2 = { t1, t2, t3 };

    for( auto it : agenda1 )
        std::cout << TimeTask::converter.to_bytes(it.towString());

    return 0;
}

What am I doing wrong here? I don't see around any multiple definition for to_date and from_time_point (the function my compiler, which is g++, is complaining for).


Solution

  • You should mark these functions as inline. Because your header file not only declares, but also defines this function. And when included from multiple translation units, both of these will compile an instance of that function, and you will get an error during linking.

    See the one-definition rule ([basic.def.odr]) for details:

    1. Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see [class.ctor], [class.dtor] and [class.copy]). An inline function or variable shall be defined in every translation unit in which it is odr-used outside of a discarded statement.

    /../

    1. There can be more than one definition of a class type, enumeration type, inline function with external linkage ([dcl.inline]), inline variable with external linkage ([dcl.inline]), class template, non-static function template, static data member of a class template, member function of a class template, or template specialization for which some template parameters are not specified ([temp.spec], [temp.class.spec]) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements.